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

下面说明一些重要函数:

1、  mmc_alloc_host

   /**

 *    mmc_alloc_host - initialise the per-host structure.

 *    @extra: sizeof private data structure

 *    @dev: pointer to host device model structure

 *

 *    Initialise the per-host structure.

 */

struct mmc_host *mmc_alloc_host(int extra, struct device *dev)

{

       struct mmc_host *host;

 

       host = mmc_alloc_host_sysfs(extra, dev);

       if (host) {

              spin_lock_init(&host->lock);

              init_waitqueue_head(&host->wq);

              INIT_LIST_HEAD(&host->cards);

              INIT_WORK(&host->detect, mmc_rescan, host);

 

              /*

               * By default, hosts do not support SGIO or large requests.

               * They have to set these according to their abilities.

               */

              host->max_hw_segs = 1;

              host->max_phys_segs = 1;

              host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);

              host->max_seg_size = PAGE_CACHE_SIZE;

       }

 

       return host;

}

这里面启动了一个延时工作队列,会启动mmc_rescan函数;

2、  mmc_add_host(mmc);函数

   调用mmc_add_host的最终结果是device_add(&host->class->dev)(所以在/sys/class/mmc/目录下出现mmc0文件)
   
并会调用mmc_power_off(host);mmc_detect_change(host, 0);
    mmc_power_off
函数比较简单,顾名思义,它是让SD/MMC卡停止工作的,相应的,此函数就会配置相应的IO口以及时钟等。
我们来看看mmc_detect_change函数吧。
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
    mmc_schedule_delayed_work(&host->detect, delay);
}
queue_delayed_work
host->detect提交到workqueue工作对列中。
相应定义:
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
workqueue = create_singlethread_workqueue("kmmcd")

所以,当此delayed_work执行的时候,mmc_rescan将会被调用;

 

static void mmc_rescan(void *data)

{

       struct mmc_host *host = data;

       struct list_head *l, *n;

       unsigned char power_mode;

/*
    驱动中使用mmc_claim_host(host);来得知,当前mmc控制器是否被占用,当前mmc控制器如果被占用,那么 host->claimed = 1;否则为0,如果为1,那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的操作完成之后,执行 mmc_release_host()的时候,会激活登记到等待队列&host->wq中的其他程序获得mmc主控制器的物理使用权*/

       mmc_claim_host(host);//这个函数和mmc_release_host(host);配对使用,相当于一把锁,就是在同一个时间只有一个sd卡可以保持和主控制器通讯;

 

       /*

        * Check for removed cards and newly inserted ones. We check for

        * removed cards first so we can intelligently re-select the VDD.

        */

       power_mode = host->ios.power_mode;

       if (power_mode == MMC_POWER_ON) //最开始,卡是power_off

              mmc_check_cards(host);

 

       mmc_setup(host);//set power_mode = MMC_POWER_ON

       /*

        * Some broken cards process CMD1 even in stand-by state. There is

        * no reply, but an ILLEGAL_COMMAND error is cached and returned

        * after next command. We poll for card status here to clear any

        * possibly pending error.

        */

       if (power_mode == MMC_POWER_ON)

              mmc_check_cards(host);

 

 

       if (!list_empty(&host->cards)) {

              /*

               * (Re-)calculate the fastest clock rate which the

               * attached cards and the host support.

               */

              host->ios.clock = mmc_calculate_clock(host);

              mmc_set_ios(host);

       }

 

       mmc_release_host(host);//释放卡对主机的持有权

 

       //查看devices链表中是否有卡插入,如果有就会调用mmc_register_card(card)

    //该函数里面调用device_add(&card->dev);将设备加入到devices表中,调用bus_attach_device(dev)-> device_attach(dev);如果取得存在直接调用device_bind_driver(dev),设备与取得绑定到一起;没有则需要到总线上面去查找,函数__device_attach-> driver_probe_device(drv, dev);到这里就是如同driver加到总线列表中一样,调用bus中的matchprobe函数,如果匹配成功调用device_bind_driver(dev)函数即可;

       list_for_each_safe(l, n, &host->cards) {

              struct mmc_card *card = mmc_list_to_card(l);

 

              /*

               * If this is a new and good card, register it.

               */

              if (!mmc_card_present(card) && !mmc_card_dead(card)) {

                     if (mmc_register_card(card))

                            mmc_card_set_dead(card);

                     else

                            mmc_card_set_present(card);

              }

 

              /*

               * If this card is dead, destroy it.

               */

              if (mmc_card_dead(card)) {

                     list_del(&card->node);

                     mmc_remove_card(card);

              }

       }

 

       /*

        * If we discover that there are no cards on the

        * bus, turn off the clock and power down.

        */

       if (list_empty(&host->cards))

              mmc_power_off(host);

}

还记得davinci_probe函数里面有个定时器吗,调用davinci_mmc_check_status函数,发现卡的插入和拔出,里面会调用mmc_detect_change(host->mmc, 0);

static void davinci_mmc_check_status(unsigned long data)

{

       unsigned long flags;

       struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;

       if (!host->is_card_busy) {

              if (host->old_card_state ^ host->new_card_state) {

                     davinci_reinit_chan(host);

                     init_mmcsd_host(host);

                     mmc_detect_change(host->mmc, 0);

                     spin_lock_irqsave(&host->mmc_lock, flags);

                     host->old_card_state = host->new_card_state;

                     spin_unlock_irqrestore(&host->mmc_lock, flags);

              } else {

                     mmc_check_card(data);

              }

 

       }

       mod_timer(&host->timer, jiffies + MULTIPLIER_TO_HZ * HZ);

}

这个函数会激活mmc_rescan,来到mmc_setup这里,此时mmc_setup调用mmc_discover_cardsCreate a mmc_card entry for each discovered cardadd new card to list.同时还会调用mmc_read_switch_caps或者mmc_process_ext_csds来实现对大容量卡的支持(> 4G );从而实现对卡拔出和插入的检查;

你可能感兴趣的:(职场,driver,休闲,mmc,Davinci)