MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / mmc / card / block.c
blobdda7c1a01933a4a0bede14d36a78397dcd43eae8
1 /*
2 * Block driver for media (i.e., flash cards)
4 * Copyright 2002 Hewlett-Packard Company
5 * Copyright 2005-2007 Pierre Ossman
7 * Use consistent with the GNU GPL is permitted,
8 * provided that this copyright notice is
9 * preserved in its entirety in all copies and derived works.
11 * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
12 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
13 * FITNESS FOR ANY PARTICULAR PURPOSE.
15 * Many thanks to Alessandro Rubini and Jonathan Corbet!
17 * Author: Andrew Christian
18 * 28 May 2002
20 #include <linux/moduleparam.h>
21 #include <linux/module.h>
22 #include <linux/init.h>
24 #include <linux/kernel.h>
25 #include <linux/fs.h>
26 #include <linux/errno.h>
27 #include <linux/hdreg.h>
28 #include <linux/kdev_t.h>
29 #include <linux/blkdev.h>
30 #if 0 // mask by Victor Yu. 12-02-2008
31 #include <linux/mutex.h>
32 #endif
33 #include <linux/scatterlist.h>
35 #include <linux/mmc/card.h>
36 #include <linux/mmc/host.h>
37 #include <linux/mmc/mmc.h>
38 #include <linux/mmc/sd.h>
40 #include <asm/system.h>
41 #include <asm/uaccess.h>
43 #include "queue.h"
45 #if ( defined CONFIG_ARCH_W341 ) || (defined CONFIG_ARCH_W345 ) || ( defined CONFIG_ARCH_W345_IMP1 )
46 #include <asm/arch/gpio.h>
47 #endif
49 #if 1 // add by Victor Yu. 12-02-2008
50 #undef MMC_BLOCK_MAJOR
51 #define MMC_BLOCK_MAJOR 121
52 #endif
55 * max 8 partitions per card
57 #define MMC_SHIFT 3
59 #if ( defined CONFIG_ARCH_W341 ) || (defined CONFIG_ARCH_W345 ) || (defined CONFIG_ARCH_W345_IMP1 )
60 #define SD_LED ( 1 << 19 )
61 #endif
64 * There is one mmc_blk_data per slot.
66 struct mmc_blk_data {
67 spinlock_t lock;
68 struct gendisk *disk;
69 struct mmc_queue queue;
71 unsigned int usage;
72 unsigned int block_bits;
73 unsigned int read_only;
76 #if 0 // mask by Victor Yu. 12-02-2008
77 static DEFINE_MUTEX(open_lock);
78 #else
79 static DECLARE_MUTEX(open_lock);
80 #endif
82 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
84 struct mmc_blk_data *md;
86 #if 0 // mask by Victor Yu. 12-02-2008
87 mutex_lock(&open_lock);
88 #else
89 down(&open_lock);
90 #endif
91 md = disk->private_data;
92 if (md && md->usage == 0)
93 md = NULL;
94 if (md)
95 md->usage++;
96 #if 0 //mask by Victor Yu. 12-02-2008
97 mutex_unlock(&open_lock);
98 #else
99 up(&open_lock);
100 #endif
102 return md;
105 static void mmc_blk_put(struct mmc_blk_data *md)
107 #if 0 // mask by Victor Yu. 12-02-2008
108 mutex_lock(&open_lock);
109 #else
110 down(&open_lock);
111 #endif
112 md->usage--;
113 if (md->usage == 0) {
114 put_disk(md->disk);
115 kfree(md);
117 #if 0 //mask by Victor Yu. 12-02-2008
118 mutex_unlock(&open_lock);
119 #else
120 up(&open_lock);
121 #endif
124 static int mmc_blk_open(struct inode *inode, struct file *filp)
126 struct mmc_blk_data *md;
127 int ret = -ENXIO;
129 md = mmc_blk_get(inode->i_bdev->bd_disk);
130 if (md) {
131 if (md->usage == 2)
132 check_disk_change(inode->i_bdev);
133 ret = 0;
135 if ((filp->f_mode & FMODE_WRITE) && md->read_only)
136 ret = -EROFS;
139 return ret;
142 static int mmc_blk_release(struct inode *inode, struct file *filp)
144 struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
146 mmc_blk_put(md);
147 return 0;
150 #if 0 // mask by Victor Yu. 12-02-2008
151 static int
152 mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
154 geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
155 geo->heads = 4;
156 geo->sectors = 16;
157 return 0;
159 #else
160 static int
161 mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
163 struct block_device *bdev = inode->i_bdev;
165 if (cmd == HDIO_GETGEO) {
166 struct hd_geometry geo;
168 memset(&geo, 0, sizeof(struct hd_geometry));
170 geo.cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
171 geo.heads = 4;
172 geo.sectors = 16;
173 geo.start = get_start_sect(bdev);
175 return copy_to_user((void __user *)arg, &geo, sizeof(geo))
176 ? -EFAULT : 0;
179 return -ENOTTY;
181 #endif
183 static struct block_device_operations mmc_bdops = {
184 .open = mmc_blk_open,
185 .release = mmc_blk_release,
186 #if 0 // mask by Victor Yu. 12-02-2008
187 .getgeo = mmc_blk_getgeo,
188 #else
189 .ioctl = mmc_blk_ioctl,
190 #endif
191 .owner = THIS_MODULE,
194 struct mmc_blk_request {
195 struct mmc_request mrq;
196 struct mmc_command cmd;
197 struct mmc_command stop;
198 struct mmc_data data;
201 static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
203 int err;
204 u32 blocks;
206 struct mmc_request mrq;
207 struct mmc_command cmd;
208 struct mmc_data data;
209 unsigned int timeout_us;
211 struct scatterlist sg;
213 memset(&cmd, 0, sizeof(struct mmc_command));
215 cmd.opcode = MMC_APP_CMD;
216 cmd.arg = card->rca << 16;
217 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
219 err = mmc_wait_for_cmd(card->host, &cmd, 0);
220 if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
221 return (u32)-1;
223 memset(&cmd, 0, sizeof(struct mmc_command));
225 cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
226 cmd.arg = 0;
227 cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
229 memset(&data, 0, sizeof(struct mmc_data));
231 data.timeout_ns = card->csd.tacc_ns * 100;
232 data.timeout_clks = card->csd.tacc_clks * 100;
234 timeout_us = data.timeout_ns / 1000;
235 timeout_us += data.timeout_clks * 1000 /
236 (card->host->ios.clock / 1000);
238 if (timeout_us > 100000) {
239 data.timeout_ns = 100000000;
240 data.timeout_clks = 0;
243 data.blksz = 4;
244 data.blocks = 1;
245 data.flags = MMC_DATA_READ;
246 data.sg = &sg;
247 data.sg_len = 1;
249 memset(&mrq, 0, sizeof(struct mmc_request));
251 mrq.cmd = &cmd;
252 mrq.data = &data;
254 #if 0 // mask by Victor Yu. 12-02-2008
255 sg_init_one(&sg, &blocks, 4);
256 #else
257 blocks = 0;
258 sg_init_one(&sg, (u8 *)&blocks, 4);
259 #endif
261 mmc_wait_for_req(card->host, &mrq);
263 if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
264 return (u32)-1;
266 blocks = ntohl(blocks);
268 return blocks;
271 static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
273 #if 0 // mask by Victor Yu. 12-03-2008
274 struct mmc_blk_data *md = mq->data;
275 struct mmc_card *card = md->queue.card;
276 #else
277 struct mmc_blk_data *md;
278 struct mmc_card *card;
279 #endif
280 struct mmc_blk_request brq;
281 int ret = 1, sg_pos, data_size;
284 #if 1 // add by Victor Yu. 12-03-2008
285 md = mq->data;
286 if ( md == NULL ) {
287 return 0;
289 card = md->queue.card;
290 if ( card == NULL ) {
291 return 0;
293 if ( card->host == NULL ) {
294 return 0;
296 #endif
298 mmc_claim_host(card->host);
300 do {
301 struct mmc_command cmd;
302 u32 readcmd, writecmd;
304 memset(&brq, 0, sizeof(struct mmc_blk_request));
305 brq.mrq.cmd = &brq.cmd;
306 brq.mrq.data = &brq.data;
308 brq.cmd.arg = req->sector;
309 if (!mmc_card_blockaddr(card))
310 brq.cmd.arg <<= 9;
311 brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
312 brq.data.blksz = 1 << md->block_bits;
313 brq.stop.opcode = MMC_STOP_TRANSMISSION;
314 brq.stop.arg = 0;
315 brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
316 brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
317 if (brq.data.blocks > card->host->max_blk_count)
318 brq.data.blocks = card->host->max_blk_count;
320 mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
323 * If the host doesn't support multiple block writes, force
324 * block writes to single block. SD cards are excepted from
325 * this rule as they support querying the number of
326 * successfully written sectors.
328 if (rq_data_dir(req) != READ &&
329 !(card->host->caps & MMC_CAP_MULTIWRITE) &&
330 !mmc_card_sd(card))
331 brq.data.blocks = 1;
333 if (brq.data.blocks > 1) {
334 brq.data.flags |= MMC_DATA_MULTI;
335 brq.mrq.stop = &brq.stop;
336 readcmd = MMC_READ_MULTIPLE_BLOCK;
337 writecmd = MMC_WRITE_MULTIPLE_BLOCK;
338 } else {
339 brq.mrq.stop = NULL;
340 readcmd = MMC_READ_SINGLE_BLOCK;
341 writecmd = MMC_WRITE_BLOCK;
344 if (rq_data_dir(req) == READ) {
345 brq.cmd.opcode = readcmd;
346 brq.data.flags |= MMC_DATA_READ;
347 } else {
348 brq.cmd.opcode = writecmd;
349 brq.data.flags |= MMC_DATA_WRITE;
352 brq.data.sg = mq->sg;
353 brq.data.sg_len = mmc_queue_map_sg(mq);
355 mmc_queue_bounce_pre(mq);
357 if (brq.data.blocks !=
358 (req->nr_sectors >> (md->block_bits - 9))) {
359 data_size = brq.data.blocks * brq.data.blksz;
360 for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
361 data_size -= mq->sg[sg_pos].length;
362 if (data_size <= 0) {
363 mq->sg[sg_pos].length += data_size;
364 sg_pos++;
365 break;
368 brq.data.sg_len = sg_pos;
371 mmc_wait_for_req(card->host, &brq.mrq);
373 mmc_queue_bounce_post(mq);
375 if (brq.cmd.error) {
376 printk(KERN_ERR "%s: error %d sending read/write command\n",
377 req->rq_disk->disk_name, brq.cmd.error);
378 goto cmd_err;
381 if (brq.data.error) {
382 printk(KERN_ERR "%s: error %d transferring data\n",
383 req->rq_disk->disk_name, brq.data.error);
384 goto cmd_err;
387 if (brq.stop.error) {
388 printk(KERN_ERR "%s: error %d sending stop command\n",
389 req->rq_disk->disk_name, brq.stop.error);
390 goto cmd_err;
393 if (rq_data_dir(req) != READ) {
394 do {
395 int err;
397 cmd.opcode = MMC_SEND_STATUS;
398 cmd.arg = card->rca << 16;
399 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
400 err = mmc_wait_for_cmd(card->host, &cmd, 5);
401 if (err) {
402 printk(KERN_ERR "%s: error %d requesting status\n",
403 req->rq_disk->disk_name, err);
404 goto cmd_err;
406 } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
408 #if 0
409 if (cmd.resp[0] & ~0x00000900)
410 printk(KERN_ERR "%s: status = %08x\n",
411 req->rq_disk->disk_name, cmd.resp[0]);
412 if (mmc_decode_status(cmd.resp))
413 goto cmd_err;
414 #endif
418 * A block was successfully transferred.
420 spin_lock_irq(&md->lock);
421 ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
422 if (!ret) {
424 * The whole request completed successfully.
426 add_disk_randomness(req->rq_disk);
427 blkdev_dequeue_request(req);
428 #if 0 // mask by Victor Yu. 12-02-2008
429 end_that_request_last(req, 1);
430 #else
431 end_that_request_last(req);
432 #endif
434 spin_unlock_irq(&md->lock);
435 } while (ret);
437 mmc_release_host(card->host);
439 return 1;
441 cmd_err:
443 * If this is an SD card and we're writing, we can first
444 * mark the known good sectors as ok.
446 * If the card is not SD, we can still ok written sectors
447 * if the controller can do proper error reporting.
449 * For reads we just fail the entire chunk as that should
450 * be safe in all cases.
452 if (rq_data_dir(req) != READ && mmc_card_sd(card)) {
453 u32 blocks;
454 unsigned int bytes;
456 blocks = mmc_sd_num_wr_blocks(card);
457 if (blocks != (u32)-1) {
458 if (card->csd.write_partial)
459 bytes = blocks << md->block_bits;
460 else
461 bytes = blocks << 9;
462 spin_lock_irq(&md->lock);
463 ret = end_that_request_chunk(req, 1, bytes);
464 spin_unlock_irq(&md->lock);
466 } else if (rq_data_dir(req) != READ &&
467 (card->host->caps & MMC_CAP_MULTIWRITE)) {
468 spin_lock_irq(&md->lock);
469 ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
470 spin_unlock_irq(&md->lock);
473 mmc_release_host(card->host);
475 spin_lock_irq(&md->lock);
476 while (ret) {
477 ret = end_that_request_chunk(req, 0,
478 req->current_nr_sectors << 9);
481 add_disk_randomness(req->rq_disk);
482 blkdev_dequeue_request(req);
483 #if 0 // mask by Victor Yu. 12-02-2008
484 end_that_request_last(req, 0);
485 #else
486 end_that_request_last(req);
487 #endif
488 spin_unlock_irq(&md->lock);
490 return 0;
493 #define MMC_NUM_MINORS (256 >> MMC_SHIFT)
495 static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
497 static inline int mmc_blk_readonly(struct mmc_card *card)
499 return mmc_card_readonly(card) ||
500 !(card->csd.cmdclass & CCC_BLOCK_WRITE);
503 static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
505 struct mmc_blk_data *md;
506 int devidx, ret;
508 devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
509 if (devidx >= MMC_NUM_MINORS)
510 return ERR_PTR(-ENOSPC);
511 __set_bit(devidx, dev_use);
513 #if 0 // mask by Victor Yu. 12-02-2008
514 md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
515 #else
516 md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
517 #endif
518 if (!md) {
519 ret = -ENOMEM;
520 goto out;
523 #if 1 // mask by Victor Yu. 12-02-2008
524 memset(md, 0, sizeof(struct mmc_blk_data));
525 #endif
529 * Set the read-only status based on the supported commands
530 * and the write protect switch.
532 md->read_only = mmc_blk_readonly(card);
535 * Both SD and MMC specifications state (although a bit
536 * unclearly in the MMC case) that a block size of 512
537 * bytes must always be supported by the card.
539 md->block_bits = 9;
541 md->disk = alloc_disk(1 << MMC_SHIFT);
542 if (md->disk == NULL) {
543 ret = -ENOMEM;
544 goto err_kfree;
547 spin_lock_init(&md->lock);
548 md->usage = 1;
550 ret = mmc_init_queue(&md->queue, card, &md->lock);
551 if (ret)
552 goto err_putdisk;
554 md->queue.issue_fn = mmc_blk_issue_rq;
555 md->queue.data = md;
557 md->disk->major = MMC_BLOCK_MAJOR;
558 md->disk->first_minor = devidx << MMC_SHIFT;
559 md->disk->fops = &mmc_bdops;
560 md->disk->private_data = md;
561 md->disk->queue = md->queue.queue;
562 md->disk->driverfs_dev = &card->dev;
565 * As discussed on lkml, GENHD_FL_REMOVABLE should:
567 * - be set for removable media with permanent block devices
568 * - be unset for removable block devices with permanent media
570 * Since MMC block devices clearly fall under the second
571 * case, we do not set GENHD_FL_REMOVABLE. Userspace
572 * should use the block device creation/destruction hotplug
573 * messages to tell when the card is present.
576 sprintf(md->disk->disk_name, "mmcblk%d", devidx);
578 blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
580 if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
582 * The EXT_CSD sector count is in number or 512 byte
583 * sectors.
585 set_capacity(md->disk, card->ext_csd.sectors);
586 } else {
588 * The CSD capacity field is in units of read_blkbits.
589 * set_capacity takes units of 512 bytes.
591 set_capacity(md->disk,
592 card->csd.capacity << (card->csd.read_blkbits - 9));
594 return md;
596 err_putdisk:
597 put_disk(md->disk);
598 err_kfree:
599 kfree(md);
600 out:
601 return ERR_PTR(ret);
604 static int
605 mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
607 struct mmc_command cmd;
608 int err;
610 /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
611 if (mmc_card_blockaddr(card))
612 return 0;
614 mmc_claim_host(card->host);
615 cmd.opcode = MMC_SET_BLOCKLEN;
616 cmd.arg = 1 << md->block_bits;
617 cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
618 err = mmc_wait_for_cmd(card->host, &cmd, 5);
619 mmc_release_host(card->host);
621 if (err) {
622 printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
623 md->disk->disk_name, cmd.arg, err);
624 return -EINVAL;
627 return 0;
630 #if 1 // add by Victor Yu. 12-15-2005
631 #include <linux/kmod.h>
632 static void mountsd(char *action)
634 char *argv[2], **envp, *buf, *scratch;
635 int i=0;
637 if ( in_interrupt() )
638 return;
639 if ( !current->fs->root )
640 return;
641 if ( !(envp=(char **)kmalloc(10*sizeof(char *), GFP_KERNEL)) )
642 return;
643 if ( !(buf=kmalloc(256, GFP_KERNEL)) )
644 return;
645 argv[0] = "/bin/sdpnp";
646 argv[1] = 0;
647 envp[i++] = "HOME=/";
648 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
649 scratch = buf;
650 envp[i++] = scratch;
651 scratch += sprintf(scratch, "ACTION=%s", action) + 1;
652 envp[i++] = 0;
653 call_usermodehelper(argv[0], argv, envp, 0);
654 kfree(envp);
655 kfree(buf);
657 #endif // 12-15-2005
659 static int mmc_blk_probe(struct mmc_card *card)
661 struct mmc_blk_data *md;
662 int err;
665 * Check that the card supports the command class(es) we need.
667 if (!(card->csd.cmdclass & CCC_BLOCK_READ))
668 return -ENODEV;
670 md = mmc_blk_alloc(card);
671 if (IS_ERR(md))
672 return PTR_ERR(md);
674 err = mmc_blk_set_blksize(md, card);
675 if (err)
676 goto out;
678 printk(KERN_INFO "%s: %s %s %lluKiB %s\n",
679 md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
680 (unsigned long long)(get_capacity(md->disk) >> 1),
681 md->read_only ? "(ro)" : "");
683 mmc_set_drvdata(card, md);
684 add_disk(md->disk);
685 #if 1 // add by Victor Yu. 12-15-2005
686 mountsd("add");
687 #if ( defined CONFIG_ARCH_W341 ) || ( defined CONFIG_ARCH_W345 ) || (defined CONFIG_ARCH_W345_IMP1 )
688 mcpu_gpio_inout( SD_LED , MCPU_GPIO_OUTPUT );
689 mcpu_gpio_set( SD_LED , MCPU_GPIO_LOW );
690 #endif
691 #endif // 12-15-2005
692 return 0;
694 out:
695 mmc_blk_put(md);
697 return err;
700 static void mmc_blk_remove(struct mmc_card *card)
702 #if 0 // mask by Victor Yu. 12-03-2008
703 struct mmc_blk_data *md = mmc_get_drvdata(card);
704 #else
705 struct mmc_blk_data *md;
707 md = mmc_get_drvdata(card);
708 #endif
710 if (md) {
711 int devidx;
713 #if 1 // add by Victor Yu. 12-15-2005
714 mountsd("remove");
715 #if ( defined CONFIG_ARCH_W341 ) || ( defined CONFIG_ARCH_W345 ) || (defined CONFIG_ARCH_W345_IMP1 )
716 mcpu_gpio_inout( SD_LED , MCPU_GPIO_OUTPUT );
717 mcpu_gpio_set( SD_LED , MCPU_GPIO_HIGH );
718 #endif
719 #endif // 12-15-2005
720 /* Stop new requests from getting into the queue */
721 del_gendisk(md->disk);
723 /* Then flush out any already in there */
724 mmc_cleanup_queue(&md->queue);
725 #if 1 // add by Victor Yu. 12-03-2008
726 md->disk->queue = NULL;
727 #endif
729 devidx = md->disk->first_minor >> MMC_SHIFT;
730 __clear_bit(devidx, dev_use);
732 mmc_blk_put(md);
734 mmc_set_drvdata(card, NULL);
737 #ifdef CONFIG_PM
738 static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
740 struct mmc_blk_data *md = mmc_get_drvdata(card);
742 if (md) {
743 mmc_queue_suspend(&md->queue);
745 return 0;
748 static int mmc_blk_resume(struct mmc_card *card)
750 struct mmc_blk_data *md = mmc_get_drvdata(card);
752 if (md) {
753 mmc_blk_set_blksize(md, card);
754 mmc_queue_resume(&md->queue);
756 return 0;
758 #else
759 #define mmc_blk_suspend NULL
760 #define mmc_blk_resume NULL
761 #endif
763 static struct mmc_driver mmc_driver = {
764 .drv = {
765 .name = "mmcblk",
767 .probe = mmc_blk_probe,
768 .remove = mmc_blk_remove,
769 .suspend = mmc_blk_suspend,
770 .resume = mmc_blk_resume,
773 static int __init mmc_blk_init(void)
775 int res = -ENOMEM;
777 res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
778 if (res)
779 goto out;
781 #if ( defined CONFIG_ARCH_W341 ) || ( defined CONFIG_ARCH_W345 ) || (defined CONFIG_ARCH_W345_IMP1 )
782 mcpu_gpio_inout( SD_LED , MCPU_GPIO_OUTPUT );
783 mcpu_gpio_set( SD_LED , MCPU_GPIO_HIGH );
784 #endif
785 return mmc_register_driver(&mmc_driver);
787 out:
788 return res;
791 static void __exit mmc_blk_exit(void)
793 mmc_unregister_driver(&mmc_driver);
794 unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
797 module_init(mmc_blk_init);
798 module_exit(mmc_blk_exit);
800 MODULE_LICENSE("GPL");
801 MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");