本节中主要讲述探测函数中的初始化和移除slot,首先看下初始化:
static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
struct mmc_host *mmc;
struct dw_mci_slot *slot;
mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev); //core中申请host,后面讲述
if (!mmc)
return -ENOMEM;
slot = mmc_priv(mmc); //mmc操作函数集,后面讲述
slot->id = id;
slot->mmc = mmc;
slot->host = host;
mmc->ops = &dw_mci_ops;
mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
mmc->f_max = host->bus_hz;
if (host->pdata->get_ocr)
mmc->ocr_avail = host->pdata->get_ocr(id);
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
/*
* Start with slot power disabled, it will be enabled when a card
* is detected.
*/
if (host->pdata->setpower)
host->pdata->setpower(id, 0);
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
else
mmc->caps = 0;
if (host->pdata->get_bus_wd)
if (host->pdata->get_bus_wd(slot->id) >= 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
mmc->caps |= MMC_CAP_SD_HIGHSPEED;
#ifdef CONFIG_MMC_DW_IDMAC
mmc->max_segs = host->ring_size;
mmc->max_blk_size = 65536;
mmc->max_blk_count = host->ring_size;
mmc->max_seg_size = 0x1000;
mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
#else
if (host->pdata->blk_settings) {
mmc->max_segs = host->pdata->blk_settings->max_segs;
mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
mmc->max_req_size = host->pdata->blk_settings->max_req_size;
mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
} else {
/* Useful defaults if platform data is unset. */
mmc->max_segs = 64;
mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
mmc->max_blk_count = 512;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
}
#endif /* CONFIG_MMC_DW_IDMAC */
host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
} else
regulator_enable(host->vmmc);
if (dw_mci_get_cd(mmc))
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
host->slot[id] = slot;
mmc_add_host(mmc); //初始化host,后面讲述
#if defined(CONFIG_DEBUG_FS)
dw_mci_init_debugfs(slot);
#endif
/* Card initially undetected */
slot->last_detect_state = 0;
/*
* Card may have been plugged in prior to boot so we
* need to run the detect tasklet
*/
tasklet_schedule(&host->card_tasklet);
return 0;
}
core中申请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)
{
int err;
struct mmc_host *host;
if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
return NULL;
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (!host)
return NULL;
spin_lock(&mmc_host_lock);
err = idr_get_new(&mmc_host_idr, host, &host->index);
spin_unlock(&mmc_host_lock);
if (err)
goto free;
dev_set_name(&host->class_dev, "mmc%d", host->index);
host->parent = dev;
host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);
mmc_host_clk_init(host);
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
INIT_DELAYED_WORK_DEFERRABLE(&host->disable, mmc_host_deeper_disable);
#ifdef CONFIG_PM
host->pm_notify.notifier_call = mmc_pm_notify;
#endif
/*
* By default, hosts do not support SGIO or large requests.
* They have to set these according to their abilities.
*/
host->max_segs = 1;
host->max_seg_size = PAGE_CACHE_SIZE;
host->max_req_size = PAGE_CACHE_SIZE;
host->max_blk_size = 512;
host->max_blk_count = PAGE_CACHE_SIZE / 512;
return host;
free:
kfree(host);
return NULL;
}
EXPORT_SYMBOL(mmc_alloc_host);
初始化host:
/**
* mmc_add_host - initialise host hardware
* @host: mmc host
*
* Register the host with the driver model. The host must be
* prepared to start servicing requests before this function
* completes.
*/
int mmc_add_host(struct mmc_host *host)
{
int err;
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
err = device_add(&host->class_dev);
if (err)
return err;
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
#ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host);
#endif
mmc_start_host(host);
register_pm_notifier(&host->pm_notify);
return 0;
}
EXPORT_SYMBOL(mmc_add_host);
清除slot:
static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
{
/* Shutdown detect IRQ */
if (slot->host->pdata->exit)
slot->host->pdata->exit(id);
/* Debugfs stuff is cleaned up by mmc core */
mmc_remove_host(slot->mmc); //移除host
slot->host->slot[id] = NULL;
mmc_free_host(slot->mmc); //释放host
}
移除host:
/**
* mmc_remove_host - remove host hardware
* @host: mmc host
*
* Unregister and remove all cards associated with this host,
* and power down the MMC bus. No new requests will be issued
* after this function has returned.
*/
void mmc_remove_host(struct mmc_host *host)
{
unregister_pm_notifier(&host->pm_notify);
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS
mmc_remove_host_debugfs(host);
#endif
device_del(&host->class_dev);
led_trigger_unregister_simple(host->led);
mmc_host_clk_exit(host);
}
EXPORT_SYMBOL(mmc_remove_host);
释放host
/**
* mmc_free_host - free the host structure
* @host: mmc host
*
* Free the host once all references to it have been dropped.
*/
void mmc_free_host(struct mmc_host *host)
{
spin_lock(&mmc_host_lock);
idr_remove(&mmc_host_idr, host->index);
spin_unlock(&mmc_host_lock);
put_device(&host->class_dev);
}
EXPORT_SYMBOL(mmc_free_host);
阅读(789) | 评论(0) | 转发(0) |