davinci sd卡驱动学习笔记(五)

简介:


跟着程序的流程我们来到

if (!mmc_card_present(card) && !mmc_card_dead(card)) {
            if (mmc_register_card(card))
来看

/*

 * Internal function.  Register a new MMC card with the driver model.

 */

int mmc_register_card(struct mmc_card *card)

{

       int ret;

 

       snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),

               "%s:%04x", mmc_hostname(card->host), card->rca);

 

       ret = device_add(&card->dev);

       if (ret == 0) {

              if (mmc_card_sd(card)) {

                     ret = device_create_file(&card->dev, &mmc_dev_attr_scr);

                     if (ret)

                            device_del(&card->dev);

              }

       }

       return ret;

}

int device_add(struct device *dev)

{

……………………………………….

       if ((error = device_add_attrs(dev)))

              goto AttrsError;

       if ((error = device_pm_add(dev)))

              goto PMError;

       if ((error = bus_add_device(dev)))//把设备加入到总线中

              goto BusError;

       kobject_uevent(&dev->kobj, KOBJ_ADD);

       bus_attach_device(dev);在总线中去匹配自己的驱动(那一半)

…………………………………………..

}

 

void bus_attach_device(struct device * dev)

{

       struct bus_type * bus = dev->bus;

 

       if (bus) {

              device_attach(dev);

              klist_add_tail(&dev->knode_bus, &bus->klist_devices);

       }

}

 

int device_attach(struct device * dev)

{

       int ret = 0;

 

       down(&dev->sem);

       if (dev->driver) {

              device_bind_driver(dev);

              ret = 1;

       } else

              ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);

       up(&dev->sem);

       return ret;

}

 

static int __device_attach(struct device_driver * drv, void * data)

{

       struct device * dev = data;

       return driver_probe_device(drv, dev);

}

 

device_add(&card->dev)将到相应总线mmc_bus_type上去搜索相应驱动。找到驱动后就设置dev->driver=drv,并调用mmc_bus_type总线的probe函数被调用,即mmc_bus_probe函数;该函数在mmc_sysfs.c中:

static int mmc_bus_probe(struct device *dev)

{

       struct mmc_driver *drv = to_mmc_driver(dev->driver);

       struct mmc_card *card = dev_to_mmc_card(dev);

 

       return drv->probe(card);

}

然后会调用mmc_block.c中的probe函数,mmc_blk_probe()首先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程mmc_queue_thread()

static int mmc_blk_probe(struct mmc_card *card)

{

       struct mmc_blk_data *md;

       int err;

 

       /*

        * Check that the card supports the command class(es) we need.

        */

       if (!(card->csd.cmdclass & CCC_BLOCK_READ))

              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;

 

       //出入sd卡,驱动起来的时候会打印

       printk(KERN_INFO "%s: %s %s %lluKiB %s\n",

              md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),

              (unsigned long long)(get_capacity(md->disk) >> 1),

              md->read_only ? "(ro)" : "");

我的打印如下:

Enabling 1 bit mode

Enabling 1 bit mode

Enabling 1 bit mode

Enabling 1 bit mode

Enabling 1 bit mode

Enabling 1 bit mode

Enabling 1 bit mode

Enabling 1 bit mode

Enabling 4 bit mode

Enabling 4 bit mode

mmcblk0: mmc0:88e4 SU16G 15558144KiB

 mmcblk0:<7>mmc0: starting CMD7 arg 88e40000 flags 00000015

Enabling 4 bit mode

 p1

……………………………………………………

       mmc_set_drvdata(card, md);

       add_disk(md->disk);

       return 0;

 

 out:

       mmc_blk_put(md);

 

       return err;

}

struct mmc_blk_data封装了struct gendisk   struct mmc_queue,struct mmc_queue封装了struct mmc_cardstruct request

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)  //32

              return ERR_PTR(-ENOSPC);

       __set_bit(devidx, dev_use);

 

       md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);

       if (!md) {

              ret = -ENOMEM;

              goto out;

       }

 

       memset(md, 0, sizeof(struct mmc_blk_data));

 

       /*

        * Set the read-only status based on the supported commands

        * and the write protect switch.

        */

       md->read_only = mmc_blk_readonly(card);

 

       /*

        * 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.

        */

       md->block_bits = 9;  // 29次方为512

 

       md->disk = alloc_disk(1 << MMC_SHIFT);

       if (md->disk == NULL) {

              ret = -ENOMEM;

              goto err_kfree;

       }

 

       spin_lock_init(&md->lock);

       md->usage = 1;

 

       ret = mmc_init_queue(&md->queue, card, &md->lock); //创建一个队列

       if (ret)

              goto err_putdisk;

 

       md->queue.prep_fn = mmc_blk_prep_rq;

       md->queue.issue_fn = mmc_blk_issue_rq;//请求传输函数

       md->queue.data = md;

 

       md->disk->major = major;

       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);

 

       /*

        * 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));

       return md;

 

 err_putdisk:

       put_disk(md->disk);

 err_kfree:

       kfree(md);

 out:

       return ERR_PTR(ret);

}

 

/**

 * mmc_init_queue - initialise a queue structure.

 * @mq: mmc queue

 * @card: mmc card to attach this queue

 * @lock: queue lock

 *

 * Initialise a MMC card request queue.

 */

int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)

{

       struct mmc_host *host = card->host;

       u64 limit = BLK_BOUNCE_HIGH;

       int ret;

 

       if (host->dev->dma_mask && *host->dev->dma_mask)

              limit = *host->dev->dma_mask;

 

       mq->card = card;

       mq->queue = blk_init_queue(mmc_request, lock);

       if (!mq->queue)

              return -ENOMEM;

 

       blk_queue_prep_rq(mq->queue, mmc_prep_request);

       blk_queue_bounce_limit(mq->queue, limit);

       blk_queue_max_sectors(mq->queue, host->max_sectors);

       blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);

       blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);

       blk_queue_max_segment_size(mq->queue, host->max_seg_size);

 

       mq->queue->queuedata = mq;

       mq->req = NULL;

 

       mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,

                      GFP_KERNEL);

       if (!mq->sg) {

              ret = -ENOMEM;

              goto cleanup_queue;

       }

 

       init_MUTEX(&mq->thread_sem);

//这里就是在读写sd卡时你所看到的内核线程mmcqd

       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");

       if (IS_ERR(mq->thread)) {

              ret = PTR_ERR(mq->thread);

              goto free_sg;

       }

 

       return 0;

 

 free_sg:

       kfree(mq->sg);

       mq->sg = NULL;

 cleanup_queue:

       blk_cleanup_queue(mq->queue);

       return ret;

}

至此,驱动向系统添加了一个块设备。
请求处理过程:
mmc_request--->mmc_queue_thread----->mmc_blk_issue_rq---->mmc_wait_for_req--->mmc_start_request---->
 mmc_davinci_ops里边的mmc_davinci_request就被调用了;




本文转自 曾永刚 51CTO博客,原文链接:http://blog.51cto.com/zyg0227/565390

相关实践学习
RocketMQ一站式入门使用
从源码编译、部署broker、部署namesrv,使用java客户端首发消息等一站式入门RocketMQ。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
7月前
|
Linux
从零开始写linux字符设备驱动程序(四)(基于友善之臂tiny4412开发板)
从零开始写linux字符设备驱动程序(四)(基于友善之臂tiny4412开发板)
89 0
|
7月前
|
编解码 Linux 数据格式
Linux MIPI DSI LCD设备驱动开发调试细节学习笔记(一)
Linux MIPI DSI LCD设备驱动开发调试细节学习笔记(一)
1156 0
|
7月前
|
Linux
从零开始写linux字符设备驱动程序(二)(基于友善之臂tiny4412开发板)
从零开始写linux字符设备驱动程序(二)(基于友善之臂tiny4412开发板)
49 0
|
7月前
|
Linux
从零开始写linux字符设备驱动程序(三)(基于友善之臂tiny4412开发板)
从零开始写linux字符设备驱动程序(三)(基于友善之臂tiny4412开发板)
44 0
|
存储 异构计算 内存技术
树莓派4B:扩展系统到整个SD卡
树莓派4B:扩展系统到整个SD卡
318 0
树莓派4B:扩展系统到整个SD卡