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);從而實現對卡拔出和插入的檢查;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章