block.c 14.1 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
/*
 * Block driver for media (i.e., flash cards)
 *
 * Copyright 2002 Hewlett-Packard Company
5
 * Copyright 2005-2008 Pierre Ossman
Linus Torvalds's avatar
Linus Torvalds committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * Use consistent with the GNU GPL is permitted,
 * provided that this copyright notice is
 * preserved in its entirety in all copies and derived works.
 *
 * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
 * FITNESS FOR ANY PARTICULAR PURPOSE.
 *
 * Many thanks to Alessandro Rubini and Jonathan Corbet!
 *
 * Author:  Andrew Christian
 *          28 May 2002
 */
#include <linux/moduleparam.h>
#include <linux/module.h>
#include <linux/init.h>

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/hdreg.h>
#include <linux/kdev_t.h>
#include <linux/blkdev.h>
30
#include <linux/mutex.h>
31
#include <linux/scatterlist.h>
32
#include <linux/string_helpers.h>
Linus Torvalds's avatar
Linus Torvalds committed
33
34

#include <linux/mmc/card.h>
35
#include <linux/mmc/host.h>
Pierre Ossman's avatar
Pierre Ossman committed
36
37
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
Linus Torvalds's avatar
Linus Torvalds committed
38
39
40
41

#include <asm/system.h>
#include <asm/uaccess.h>

42
#include "queue.h"
Linus Torvalds's avatar
Linus Torvalds committed
43
44
45
46
47

/*
 * max 8 partitions per card
 */
#define MMC_SHIFT	3
48
49
#define MMC_NUM_MINORS	(256 >> MMC_SHIFT)

50
static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
Linus Torvalds's avatar
Linus Torvalds committed
51
52
53
54
55
56
57
58
59
60
61

/*
 * There is one mmc_blk_data per slot.
 */
struct mmc_blk_data {
	spinlock_t	lock;
	struct gendisk	*disk;
	struct mmc_queue queue;

	unsigned int	usage;
	unsigned int	block_bits;
62
	unsigned int	read_only;
Linus Torvalds's avatar
Linus Torvalds committed
63
64
};

65
static DEFINE_MUTEX(open_lock);
Linus Torvalds's avatar
Linus Torvalds committed
66
67
68
69
70

static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
	struct mmc_blk_data *md;

71
	mutex_lock(&open_lock);
Linus Torvalds's avatar
Linus Torvalds committed
72
73
74
75
76
	md = disk->private_data;
	if (md && md->usage == 0)
		md = NULL;
	if (md)
		md->usage++;
77
	mutex_unlock(&open_lock);
Linus Torvalds's avatar
Linus Torvalds committed
78
79
80
81
82
83

	return md;
}

static void mmc_blk_put(struct mmc_blk_data *md)
{
84
	mutex_lock(&open_lock);
Linus Torvalds's avatar
Linus Torvalds committed
85
86
	md->usage--;
	if (md->usage == 0) {
87
88
89
		int devidx = md->disk->first_minor >> MMC_SHIFT;
		__clear_bit(devidx, dev_use);

Linus Torvalds's avatar
Linus Torvalds committed
90
91
92
		put_disk(md->disk);
		kfree(md);
	}
93
	mutex_unlock(&open_lock);
Linus Torvalds's avatar
Linus Torvalds committed
94
95
96
97
98
99
100
101
102
103
104
105
}

static int mmc_blk_open(struct inode *inode, struct file *filp)
{
	struct mmc_blk_data *md;
	int ret = -ENXIO;

	md = mmc_blk_get(inode->i_bdev->bd_disk);
	if (md) {
		if (md->usage == 2)
			check_disk_change(inode->i_bdev);
		ret = 0;
Pierre Ossman's avatar
Pierre Ossman committed
106

107
108
		if ((filp->f_mode & FMODE_WRITE) && md->read_only) {
			mmc_blk_put(md);
Pierre Ossman's avatar
Pierre Ossman committed
109
			ret = -EROFS;
110
		}
Linus Torvalds's avatar
Linus Torvalds committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
	}

	return ret;
}

static int mmc_blk_release(struct inode *inode, struct file *filp)
{
	struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;

	mmc_blk_put(md);
	return 0;
}

static int
125
mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
Linus Torvalds's avatar
Linus Torvalds committed
126
{
127
128
129
130
	geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
	geo->heads = 4;
	geo->sectors = 16;
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
131
132
133
134
135
}

static struct block_device_operations mmc_bdops = {
	.open			= mmc_blk_open,
	.release		= mmc_blk_release,
136
	.getgeo			= mmc_blk_getgeo,
Linus Torvalds's avatar
Linus Torvalds committed
137
138
139
140
141
142
143
144
145
146
	.owner			= THIS_MODULE,
};

struct mmc_blk_request {
	struct mmc_request	mrq;
	struct mmc_command	cmd;
	struct mmc_command	stop;
	struct mmc_data		data;
};

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
{
	int err;
	u32 blocks;

	struct mmc_request mrq;
	struct mmc_command cmd;
	struct mmc_data data;
	unsigned int timeout_us;

	struct scatterlist sg;

	memset(&cmd, 0, sizeof(struct mmc_command));

	cmd.opcode = MMC_APP_CMD;
	cmd.arg = card->rca << 16;
David Brownell's avatar
David Brownell committed
163
	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
164
165

	err = mmc_wait_for_cmd(card->host, &cmd, 0);
David Brownell's avatar
David Brownell committed
166
167
168
	if (err)
		return (u32)-1;
	if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
169
170
171
172
173
174
		return (u32)-1;

	memset(&cmd, 0, sizeof(struct mmc_command));

	cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
	cmd.arg = 0;
David Brownell's avatar
David Brownell committed
175
	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

	memset(&data, 0, sizeof(struct mmc_data));

	data.timeout_ns = card->csd.tacc_ns * 100;
	data.timeout_clks = card->csd.tacc_clks * 100;

	timeout_us = data.timeout_ns / 1000;
	timeout_us += data.timeout_clks * 1000 /
		(card->host->ios.clock / 1000);

	if (timeout_us > 100000) {
		data.timeout_ns = 100000000;
		data.timeout_clks = 0;
	}

	data.blksz = 4;
	data.blocks = 1;
	data.flags = MMC_DATA_READ;
	data.sg = &sg;
	data.sg_len = 1;

	memset(&mrq, 0, sizeof(struct mmc_request));

	mrq.cmd = &cmd;
	mrq.data = &data;

	sg_init_one(&sg, &blocks, 4);

	mmc_wait_for_req(card->host, &mrq);

Pierre Ossman's avatar
Pierre Ossman committed
206
	if (cmd.error || data.error)
207
208
209
210
211
212
213
		return (u32)-1;

	blocks = ntohl(blocks);

	return blocks;
}

Linus Torvalds's avatar
Linus Torvalds committed
214
215
216
217
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
	struct mmc_blk_data *md = mq->data;
	struct mmc_card *card = md->queue.card;
218
	struct mmc_blk_request brq;
219
220
	int ret = 1, data_size, i;
	struct scatterlist *sg;
Linus Torvalds's avatar
Linus Torvalds committed
221

222
	mmc_claim_host(card->host);
Linus Torvalds's avatar
Linus Torvalds committed
223
224
225

	do {
		struct mmc_command cmd;
226
		u32 readcmd, writecmd;
Linus Torvalds's avatar
Linus Torvalds committed
227
228
229
230
231

		memset(&brq, 0, sizeof(struct mmc_blk_request));
		brq.mrq.cmd = &brq.cmd;
		brq.mrq.data = &brq.data;

232
233
234
		brq.cmd.arg = req->sector;
		if (!mmc_card_blockaddr(card))
			brq.cmd.arg <<= 9;
David Brownell's avatar
David Brownell committed
235
		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
236
		brq.data.blksz = 1 << md->block_bits;
Linus Torvalds's avatar
Linus Torvalds committed
237
238
		brq.stop.opcode = MMC_STOP_TRANSMISSION;
		brq.stop.arg = 0;
David Brownell's avatar
David Brownell committed
239
		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
240
241
242
		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
		if (brq.data.blocks > card->host->max_blk_count)
			brq.data.blocks = card->host->max_blk_count;
Linus Torvalds's avatar
Linus Torvalds committed
243

Russell King's avatar
Russell King committed
244
		if (brq.data.blocks > 1) {
David Brownell's avatar
David Brownell committed
245
246
247
248
249
250
			/* SPI multiblock writes terminate using a special
			 * token, not a STOP_TRANSMISSION request.
			 */
			if (!mmc_host_is_spi(card->host)
					|| rq_data_dir(req) == READ)
				brq.mrq.stop = &brq.stop;
251
252
			readcmd = MMC_READ_MULTIPLE_BLOCK;
			writecmd = MMC_WRITE_MULTIPLE_BLOCK;
Russell King's avatar
Russell King committed
253
254
		} else {
			brq.mrq.stop = NULL;
255
256
257
258
259
260
261
262
263
264
			readcmd = MMC_READ_SINGLE_BLOCK;
			writecmd = MMC_WRITE_BLOCK;
		}

		if (rq_data_dir(req) == READ) {
			brq.cmd.opcode = readcmd;
			brq.data.flags |= MMC_DATA_READ;
		} else {
			brq.cmd.opcode = writecmd;
			brq.data.flags |= MMC_DATA_WRITE;
Russell King's avatar
Russell King committed
265
		}
Linus Torvalds's avatar
Linus Torvalds committed
266

267
268
		mmc_set_data_timeout(&brq.data, card);

Linus Torvalds's avatar
Linus Torvalds committed
269
		brq.data.sg = mq->sg;
270
271
272
		brq.data.sg_len = mmc_queue_map_sg(mq);

		mmc_queue_bounce_pre(mq);
Linus Torvalds's avatar
Linus Torvalds committed
273

274
275
276
277
		/*
		 * Adjust the sg list so it is the same size as the
		 * request.
		 */
278
279
280
		if (brq.data.blocks !=
		    (req->nr_sectors >> (md->block_bits - 9))) {
			data_size = brq.data.blocks * brq.data.blksz;
281
282
			for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
				data_size -= sg->length;
283
				if (data_size <= 0) {
284
285
					sg->length += data_size;
					i++;
286
287
288
					break;
				}
			}
289
			brq.data.sg_len = i;
290
291
		}

Linus Torvalds's avatar
Linus Torvalds committed
292
		mmc_wait_for_req(card->host, &brq.mrq);
293
294
295

		mmc_queue_bounce_post(mq);

296
297
298
299
300
		/*
		 * Check for errors here, but don't jump to cmd_err
		 * until later as we need to wait for the card to leave
		 * programming mode even when things go wrong.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
		if (brq.cmd.error) {
			printk(KERN_ERR "%s: error %d sending read/write command\n",
			       req->rq_disk->disk_name, brq.cmd.error);
		}

		if (brq.data.error) {
			printk(KERN_ERR "%s: error %d transferring data\n",
			       req->rq_disk->disk_name, brq.data.error);
		}

		if (brq.stop.error) {
			printk(KERN_ERR "%s: error %d sending stop command\n",
			       req->rq_disk->disk_name, brq.stop.error);
		}

David Brownell's avatar
David Brownell committed
316
		if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
317
318
319
320
321
322
323
324
325
326
327
328
			do {
				int err;

				cmd.opcode = MMC_SEND_STATUS;
				cmd.arg = card->rca << 16;
				cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
				err = mmc_wait_for_cmd(card->host, &cmd, 5);
				if (err) {
					printk(KERN_ERR "%s: error %d requesting status\n",
					       req->rq_disk->disk_name, err);
					goto cmd_err;
				}
329
330
331
332
333
334
335
				/*
				 * Some cards mishandle the status bits,
				 * so make sure to check both the busy
				 * indication and the card state.
				 */
			} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
				(R1_CURRENT_STATE(cmd.resp[0]) == 7));
Linus Torvalds's avatar
Linus Torvalds committed
336
337

#if 0
338
339
340
341
342
			if (cmd.resp[0] & ~0x00000900)
				printk(KERN_ERR "%s: status = %08x\n",
				       req->rq_disk->disk_name, cmd.resp[0]);
			if (mmc_decode_status(cmd.resp))
				goto cmd_err;
Linus Torvalds's avatar
Linus Torvalds committed
343
#endif
344
		}
Linus Torvalds's avatar
Linus Torvalds committed
345

346
347
348
		if (brq.cmd.error || brq.data.error || brq.stop.error)
			goto cmd_err;

Linus Torvalds's avatar
Linus Torvalds committed
349
350
351
352
		/*
		 * A block was successfully transferred.
		 */
		spin_lock_irq(&md->lock);
353
		ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
Linus Torvalds's avatar
Linus Torvalds committed
354
355
356
		spin_unlock_irq(&md->lock);
	} while (ret);

357
	mmc_release_host(card->host);
Linus Torvalds's avatar
Linus Torvalds committed
358
359
360
361

	return 1;

 cmd_err:
362
363
364
365
366
 	/*
 	 * If this is an SD card and we're writing, we can first
 	 * mark the known good sectors as ok.
 	 *
	 * If the card is not SD, we can still ok written sectors
367
368
	 * as reported by the controller (which might be less than
	 * the real number of written sectors, but never more).
369
370
371
	 *
	 * For reads we just fail the entire chunk as that should
	 * be safe in all cases.
Linus Torvalds's avatar
Linus Torvalds committed
372
	 */
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
	if (rq_data_dir(req) != READ) {
		if (mmc_card_sd(card)) {
			u32 blocks;
			unsigned int bytes;

			blocks = mmc_sd_num_wr_blocks(card);
			if (blocks != (u32)-1) {
				if (card->csd.write_partial)
					bytes = blocks << md->block_bits;
				else
					bytes = blocks << 9;
				spin_lock_irq(&md->lock);
				ret = __blk_end_request(req, 0, bytes);
				spin_unlock_irq(&md->lock);
			}
		} else {
389
			spin_lock_irq(&md->lock);
390
			ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
391
392
			spin_unlock_irq(&md->lock);
		}
393
394
	}

395
	mmc_release_host(card->host);
396

Linus Torvalds's avatar
Linus Torvalds committed
397
	spin_lock_irq(&md->lock);
398
399
	while (ret)
		ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
Linus Torvalds's avatar
Linus Torvalds committed
400
401
402
403
404
405
	spin_unlock_irq(&md->lock);

	return 0;
}


406
407
408
409
410
411
static inline int mmc_blk_readonly(struct mmc_card *card)
{
	return mmc_card_readonly(card) ||
	       !(card->csd.cmdclass & CCC_BLOCK_WRITE);
}

Linus Torvalds's avatar
Linus Torvalds committed
412
413
414
415
416
417
418
419
420
421
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
{
	struct mmc_blk_data *md;
	int devidx, ret;

	devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
	if (devidx >= MMC_NUM_MINORS)
		return ERR_PTR(-ENOSPC);
	__set_bit(devidx, dev_use);

422
	md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
423
424
425
426
	if (!md) {
		ret = -ENOMEM;
		goto out;
	}
Linus Torvalds's avatar
Linus Torvalds committed
427
428


429
430
431
432
433
	/*
	 * Set the read-only status based on the supported commands
	 * and the write protect switch.
	 */
	md->read_only = mmc_blk_readonly(card);
Linus Torvalds's avatar
Linus Torvalds committed
434

435
	/*
436
437
438
	 * Both SD and MMC specifications state (although a bit
	 * unclearly in the MMC case) that a block size of 512
	 * bytes must always be supported by the card.
439
	 */
440
	md->block_bits = 9;
Linus Torvalds's avatar
Linus Torvalds committed
441

442
443
444
445
446
	md->disk = alloc_disk(1 << MMC_SHIFT);
	if (md->disk == NULL) {
		ret = -ENOMEM;
		goto err_kfree;
	}
Linus Torvalds's avatar
Linus Torvalds committed
447

448
449
	spin_lock_init(&md->lock);
	md->usage = 1;
Linus Torvalds's avatar
Linus Torvalds committed
450

451
452
453
	ret = mmc_init_queue(&md->queue, card, &md->lock);
	if (ret)
		goto err_putdisk;
Linus Torvalds's avatar
Linus Torvalds committed
454

455
456
	md->queue.issue_fn = mmc_blk_issue_rq;
	md->queue.data = md;
457

458
	md->disk->major	= MMC_BLOCK_MAJOR;
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
	md->disk->first_minor = devidx << MMC_SHIFT;
	md->disk->fops = &mmc_bdops;
	md->disk->private_data = md;
	md->disk->queue = md->queue.queue;
	md->disk->driverfs_dev = &card->dev;

	/*
	 * As discussed on lkml, GENHD_FL_REMOVABLE should:
	 *
	 * - be set for removable media with permanent block devices
	 * - be unset for removable block devices with permanent media
	 *
	 * Since MMC block devices clearly fall under the second
	 * case, we do not set GENHD_FL_REMOVABLE.  Userspace
	 * should use the block device creation/destruction hotplug
	 * messages to tell when the card is present.
	 */

	sprintf(md->disk->disk_name, "mmcblk%d", devidx);

	blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);

Pierre Ossman's avatar
Pierre Ossman committed
481
482
483
484
485
486
487
488
489
490
491
492
493
494
	if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
		/*
		 * The EXT_CSD sector count is in number or 512 byte
		 * sectors.
		 */
		set_capacity(md->disk, card->ext_csd.sectors);
	} else {
		/*
		 * The CSD capacity field is in units of read_blkbits.
		 * set_capacity takes units of 512 bytes.
		 */
		set_capacity(md->disk,
			card->csd.capacity << (card->csd.read_blkbits - 9));
	}
Linus Torvalds's avatar
Linus Torvalds committed
495
	return md;
496
497
498
499
500
501
502

 err_putdisk:
	put_disk(md->disk);
 err_kfree:
	kfree(md);
 out:
	return ERR_PTR(ret);
Linus Torvalds's avatar
Linus Torvalds committed
503
504
505
506
507
508
509
510
}

static int
mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
{
	struct mmc_command cmd;
	int err;

511
512
513
514
	/* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
	if (mmc_card_blockaddr(card))
		return 0;

515
	mmc_claim_host(card->host);
Linus Torvalds's avatar
Linus Torvalds committed
516
	cmd.opcode = MMC_SET_BLOCKLEN;
517
	cmd.arg = 1 << md->block_bits;
David Brownell's avatar
David Brownell committed
518
	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
Linus Torvalds's avatar
Linus Torvalds committed
519
	err = mmc_wait_for_cmd(card->host, &cmd, 5);
520
	mmc_release_host(card->host);
Linus Torvalds's avatar
Linus Torvalds committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535

	if (err) {
		printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
			md->disk->disk_name, cmd.arg, err);
		return -EINVAL;
	}

	return 0;
}

static int mmc_blk_probe(struct mmc_card *card)
{
	struct mmc_blk_data *md;
	int err;

536
537
	char cap_str[10];

538
539
540
541
	/*
	 * Check that the card supports the command class(es) we need.
	 */
	if (!(card->csd.cmdclass & CCC_BLOCK_READ))
Linus Torvalds's avatar
Linus Torvalds committed
542
543
544
545
546
547
548
549
550
551
		return -ENODEV;

	md = mmc_blk_alloc(card);
	if (IS_ERR(md))
		return PTR_ERR(md);

	err = mmc_blk_set_blksize(md, card);
	if (err)
		goto out;

552
553
554
	string_get_size(get_capacity(md->disk) << 9, STRING_UNITS_2,
			cap_str, sizeof(cap_str));
	printk(KERN_INFO "%s: %s %s %s %s\n",
Linus Torvalds's avatar
Linus Torvalds committed
555
		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
556
		cap_str, md->read_only ? "(ro)" : "");
Linus Torvalds's avatar
Linus Torvalds committed
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572

	mmc_set_drvdata(card, md);
	add_disk(md->disk);
	return 0;

 out:
	mmc_blk_put(md);

	return err;
}

static void mmc_blk_remove(struct mmc_card *card)
{
	struct mmc_blk_data *md = mmc_get_drvdata(card);

	if (md) {
573
		/* Stop new requests from getting into the queue */
Linus Torvalds's avatar
Linus Torvalds committed
574
575
		del_gendisk(md->disk);

576
577
		/* Then flush out any already in there */
		mmc_cleanup_queue(&md->queue);
Linus Torvalds's avatar
Linus Torvalds committed
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621

		mmc_blk_put(md);
	}
	mmc_set_drvdata(card, NULL);
}

#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
{
	struct mmc_blk_data *md = mmc_get_drvdata(card);

	if (md) {
		mmc_queue_suspend(&md->queue);
	}
	return 0;
}

static int mmc_blk_resume(struct mmc_card *card)
{
	struct mmc_blk_data *md = mmc_get_drvdata(card);

	if (md) {
		mmc_blk_set_blksize(md, card);
		mmc_queue_resume(&md->queue);
	}
	return 0;
}
#else
#define	mmc_blk_suspend	NULL
#define mmc_blk_resume	NULL
#endif

static struct mmc_driver mmc_driver = {
	.drv		= {
		.name	= "mmcblk",
	},
	.probe		= mmc_blk_probe,
	.remove		= mmc_blk_remove,
	.suspend	= mmc_blk_suspend,
	.resume		= mmc_blk_resume,
};

static int __init mmc_blk_init(void)
{
622
	int res;
Linus Torvalds's avatar
Linus Torvalds committed
623

624
625
	res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
	if (res)
Linus Torvalds's avatar
Linus Torvalds committed
626
627
		goto out;

628
629
630
	res = mmc_register_driver(&mmc_driver);
	if (res)
		goto out2;
Linus Torvalds's avatar
Linus Torvalds committed
631

632
633
634
	return 0;
 out2:
	unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
Linus Torvalds's avatar
Linus Torvalds committed
635
636
637
638
639
640
641
 out:
	return res;
}

static void __exit mmc_blk_exit(void)
{
	mmc_unregister_driver(&mmc_driver);
642
	unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
Linus Torvalds's avatar
Linus Torvalds committed
643
644
645
646
647
648
649
650
}

module_init(mmc_blk_init);
module_exit(mmc_blk_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");