您的位置:首页 > 运维架构 > Linux

linux设备模型之mmc,sd子系统<三>

2012-02-01 22:55 381 查看
-----------------------------------------------------------

本文系本站原创,欢迎转载!

转载请注明出处:http://blog.csdn.net/gdt_a20

-----------------------------------------------------------

####看一下重要的卡扫描函数,mmc_rescan,卡就指着他

####活着呢,


/driver/mmc/core/core.c

void mmc_rescan(struct work_struct *work)

{

static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; //扫描试验的频率段

struct mmc_host *host =

container_of(work, struct mmc_host, detect.work);

int i;

if (host->rescan_disable) //disable 直接返回

return;

mmc_bus_get(host); //增加bus引用计数

/*

* if there is a _removable_ card registered, check whether it is

* still present

*/

if (host->bus_ops && host->bus_ops->detect && !host->bus_dead

&& !(host->caps & MMC_CAP_NONREMOVABLE))

host->bus_ops->detect(host); //存在热插拔卡,不包括emmc,调用探测函数

/*

* Let mmc_bus_put() free the bus/bus_ops if we've found that

* the card is no longer present.

*/

mmc_bus_put(host); //减少引用技术,就释放

mmc_bus_get(host); //重新增加引用计数

/* if there still is a card present, stop here */

if (host->bus_ops != NULL) {

mmc_bus_put(host); //如果卡仍然存在,减少引用计数,不必探测了

goto out;

}

/*

* Only we can add a new handler, so it's safe to

* release the lock here.

*/

mmc_bus_put(host); //减少引用计数

if (host->ops->get_cd && host->ops->get_cd(host) == 0) //有卡,退出

goto out;

mmc_claim_host(host); //用于检测host是否被占用,占用则退出,否则标记成占用

for (i = 0; i < ARRAY_SIZE(freqs); i++) {

if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) //利用不同的频率探测卡

break;

if (freqs[i] <= host->f_min)

break;

}

mmc_release_host(host);

out:

if (host->caps & MMC_CAP_NEEDS_POLL) //轮询标志,设置了就会轮询

mmc_schedule_delayed_work(&host->detect, HZ);

}

#####

/**

* mmc_claim_host - exclusively claim a host

* @host: mmc host to claim

*

* Claim a host for a set of operations.

*/

static inline void mmc_claim_host(struct mmc_host *host)

{

__mmc_claim_host(host, NULL);

}

#####

/**

* __mmc_claim_host - exclusively claim a host

* @host: mmc host to claim

* @abort: whether or not the operation should be aborted

*

* Claim a host for a set of operations. If @abort is non null and

* dereference a non-zero value then this will return prematurely with

* that non-zero value without acquiring the lock. Returns zero

* with the lock held otherwise.

*/

int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)

{

DECLARE_WAITQUEUE(wait, current); //定义一个等待队列

unsigned long flags;

int stop;

might_sleep(); //调度点



add_wait_queue(&host->wq, &wait);

spin_lock_irqsave(&host->lock, flags);

while (1) {

set_current_state(TASK_UNINTERRUPTIBLE);

stop = abort ? atomic_read(abort) : 0;

if (stop || !host->claimed || host->claimer == current)

break;

spin_unlock_irqrestore(&host->lock, flags);

schedule();

spin_lock_irqsave(&host->lock, flags);

} //只有claim为空的时候还会跳出循环,否则就一直等待释放

set_current_state(TASK_RUNNING);

if (!stop) {

host->claimed = 1;

host->claimer = current;

host->claim_cnt += 1;

} else

wake_up(&host->wq);

spin_unlock_irqrestore(&host->lock, flags);

remove_wait_queue(&host->wq, &wait);

if (!stop)

mmc_host_enable(host); //使能该host

return stop;

}

#####

mmc_host_enable函数可以做一些底电流工作


#####

/**

* mmc_host_enable - enable a host.

* @host: mmc host to enable

*

* Hosts that support power saving can use the 'enable' and 'disable'

* methods to exit and enter power saving states. For more information

* see comments for struct mmc_host_ops.

*/

int mmc_host_enable(struct mmc_host *host)

{

if (!(host->caps & MMC_CAP_DISABLE))

return 0;

if (host->en_dis_recurs)

return 0;

if (host->nesting_cnt++)

return 0;

cancel_delayed_work_sync(&host->disable);

if (host->enabled)

return 0;

if (host->ops->enable) {

int err;

host->en_dis_recurs = 1;

err = host->ops->enable(host);

host->en_dis_recurs = 0;

if (err) {

pr_debug("%s: enable error %d\n",

mmc_hostname(host), err);

return err;

}

}

host->enabled = 1;

return 0;

}

#####

重点的卡探测函数,


#####

static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)

{

host->f_init = freq;

#ifdef CONFIG_MMC_DEBUG

pr_info("%s: %s: trying to init card at %u Hz\n",

mmc_hostname(host), __func__, host->f_init);

#endif

mmc_power_up(host); //电源启用

/*

* Some eMMCs (with VCCQ always on) may not be reset after power up, so

* do a hardware reset if possible.

*/

mmc_hw_reset_for_init(host); //针对emmc的硬件reset

/*

* sdio_reset sends CMD52 to reset card. Since we do not know

* if the card is being re-initialized, just send it. CMD52

* should be ignored by SD/eMMC cards.

*/

sdio_reset(host);

mmc_go_idle(host); //这部分与sd协议相关,可以结合前面内容来看

mmc_send_if_cond(host, host->ocr_avail);

/* Order's important: probe SDIO, then SD, then MMC */

if (!mmc_attach_sdio(host)) //各种卡类型探测初始化

return 0;

if (!mmc_attach_sd(host))

return 0;

if (!mmc_attach_mmc(host))

return 0;

mmc_power_off(host); //关电

return -EIO;

}

####在卡类型探测初始化过程中,重要的一个环节是和块设备的关联,这部分代码大致相同,

####例如mmc_attach_sd中,会有,

/drivers/mmc/core/sd.c

/*

* Starting point for SD card init.

*/

int mmc_attach_sd(struct mmc_host *host)

{

int err;

u32 ocr;

BUG_ON(!host);

WARN_ON(!host->claimed);

/* Make sure we are at 3.3V signalling voltage */

err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);

if (err)

return err;

/* Disable preset value enable if already set since last time */

if (host->ops->enable_preset_value)

host->ops->enable_preset_value(host, false);

err = mmc_send_app_op_cond(host, 0, &ocr);

if (err)

return err;

mmc_sd_attach_bus_ops(host); //重要,bus操作的绑定

if (host->ocr_avail_sd)

host->ocr_avail = host->ocr_avail_sd;

/*

* We need to get OCR a different way for SPI.

*/

if (mmc_host_is_spi(host)) {

mmc_go_idle(host);

err = mmc_spi_read_ocr(host, 0, &ocr);

if (err)

goto err;

}

/*

* Sanity check the voltages that the card claims to

* support.

*/

if (ocr & 0x7F) {

pr_warning("%s: card claims to support voltages "

"below the defined range. These will be ignored.\n",

mmc_hostname(host));

ocr &= ~0x7F;

}

if ((ocr & MMC_VDD_165_195) &&

!(host->ocr_avail_sd & MMC_VDD_165_195)) {

pr_warning("%s: SD card claims to support the "

"incompletely defined 'low voltage range'. This "

"will be ignored.\n", mmc_hostname(host));

ocr &= ~MMC_VDD_165_195;

}

host->ocr = mmc_select_voltage(host, ocr);

/*

* Can we support the voltage(s) of the card(s)?

*/

if (!host->ocr) {

err = -EINVAL;

goto err;

}

/*

* Detect and init the card.

*/

err = mmc_sd_init_card(host, host->ocr, NULL);

if (err)

goto err;

mmc_release_host(host);

err = mmc_add_card(host->card); //将卡加入

mmc_claim_host(host);

if (err)

goto remove_card;

return 0;

remove_card:

mmc_release_host(host);

mmc_remove_card(host->card);

host->card = NULL;

mmc_claim_host(host);

err:

mmc_detach_bus(host);

pr_err("%s: error %d whilst initialising SD card\n",

mmc_hostname(host), err);

return err;

}

#######首先是绑定操作mmc_sd_attach_bus_ops



static void mmc_sd_attach_bus_ops(struct mmc_host *host)

{

const struct mmc_bus_ops *bus_ops;

if (!mmc_card_is_removable(host)) //emmc和sd区别对待

bus_ops = &mmc_sd_ops_unsafe;

else

bus_ops = &mmc_sd_ops;

mmc_attach_bus(host, bus_ops);

}

####mmc_attach_bus函数会将bus的操作绑定到host上.

####core.c中

/*

* Assign a mmc bus handler to a host. Only one bus handler may control a

* host at any given time.

*/

void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)

{

unsigned long flags;

BUG_ON(!host);

BUG_ON(!ops);

WARN_ON(!host->claimed);

spin_lock_irqsave(&host->lock, flags);

BUG_ON(host->bus_ops);

BUG_ON(host->bus_refs);

host->bus_ops = ops; //指向对应的操作结构

host->bus_refs = 1;

host->bus_dead = 0;

spin_unlock_irqrestore(&host->lock, flags);

}

#####再看另外一个函数mmc_add_card,

####这个函数在bus.c 中,

/*

* Register a new MMC card with the driver model.

*/

int mmc_add_card(struct mmc_card *card)

{

int ret;

const char *type;

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

switch (card->type) {

case MMC_TYPE_MMC:

type = "MMC";

break;

case MMC_TYPE_SD:

type = "SD";

if (mmc_card_blockaddr(card)) {

if (mmc_card_ext_capacity(card))

type = "SDXC";

else

type = "SDHC";

}

break;

case MMC_TYPE_SDIO:

type = "SDIO";

break;

case MMC_TYPE_SD_COMBO:

type = "SD-combo";

if (mmc_card_blockaddr(card))

type = "SDHC-combo";

break;

default:

type = "?";

break;

}

if (mmc_host_is_spi(card->host)) {

pr_info("%s: new %s%s%s card on SPI\n",

mmc_hostname(card->host),

mmc_card_highspeed(card) ? "high speed " : "",

mmc_card_ddr_mode(card) ? "DDR " : "",

type);

} else {

printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",

mmc_hostname(card->host),

mmc_sd_card_uhs(card) ? "ultra high speed " :

(mmc_card_highspeed(card) ? "high speed " : ""),

mmc_card_ddr_mode(card) ? "DDR " : "",

type, card->rca);

}

#ifdef CONFIG_DEBUG_FS

mmc_add_card_debugfs(card);

#endif

ret = device_add(&card->dev);

if (ret)

return ret;

mmc_card_set_present(card);

return 0;

}



####关注一下device_add(&card->dev);会把卡作为一个设备注册,


####这个注册会触发到bus里的match操作,这部分不理解的可以回顾前面讲到的设备模型,

####这里的bus对应mmc,调用的match函数对应于bus.c中

static struct bus_type mmc_bus_type = {

.name = "mmc",

.dev_attrs = mmc_dev_attrs,

.match = mmc_bus_match,

.uevent = mmc_bus_uevent,

.probe = mmc_bus_probe,

.remove = mmc_bus_remove,

.suspend = mmc_bus_suspend,

.resume = mmc_bus_resume,

.pm = MMC_PM_OPS_PTR,

};

/*

* This currently matches any MMC driver to any MMC card - drivers

* themselves make the decision whether to drive this card in their

* probe method.

*/

static int mmc_bus_match(struct device *dev, struct device_driver *drv)

{

return 1;

}

####总为真,那么直接会触发bus的probe操作,

####

static int mmc_bus_probe(struct device *dev)

{

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

struct mmc_card *card = mmc_dev_to_card(dev);

return drv->probe(card);

}

####会调用mmc_driver 里的probe,

####这里的mmc_driver就指的是block.c中的mmc_driver,



####还是看一下,这个过程吧,

####drivers/mmc/card/block.c

static int __init mmc_blk_init(void)

{

int res;

if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)

pr_info("mmcblk: using %d minors per device\n", perdev_minors);

max_devices = 256 / perdev_minors;

res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); //注册mmc块设备,这个后面来讲

if (res)

goto out;

res = mmc_register_driver(&mmc_driver); //重点是这个

if (res)

goto out2;

return 0;

out2:

unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");

out:

return res;

}

#####

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,

};

####在bus.c中

/**

* mmc_register_driver - register a media driver

* @drv: MMC media driver

*/

int mmc_register_driver(struct mmc_driver *drv)

{

drv->drv.bus = &mmc_bus_type;

return driver_register(&drv->drv);

}

####bus类型被指定成了mmc,也就是挂到了mmc上,这样刚才的卡注册默认全部匹配,
####所以也就会直接触发block里的probe,mmc_blk_probe
####下面的东西块设备关联比较多,放到下一章来讲

总结:描述了卡的识别阶段,并没有深入到卡的具体探测,这部分结合前面的协议转换图就不难理解,这部分主要集中在sd到块设备部分的过度

下一篇主要是针对mmc中的块设备。

Thanks
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: