📄 core.c
字号:
mmc_set_ios(host);}/* * Allocate a new MMC card */struct mmc_card *mmc_alloc_card(struct mmc_host *host){ struct mmc_card *card; card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); if (!card) return ERR_PTR(-ENOMEM); mmc_init_card(card, host); return card;}/* * Apply power to the MMC stack. This is a two-stage process. * First, we enable power to the card without the clock running. * We then wait a bit for the power to stabilise. Finally, * enable the bus drivers and clock to the card. * * We must _NOT_ enable the clock prior to power stablising. * * If a host does all the power sequencing itself, ignore the * initial MMC_POWER_UP stage. */static void mmc_power_up(struct mmc_host *host){ int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); mmc_delay(1); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; mmc_set_ios(host); mmc_delay(2);}static void mmc_power_off(struct mmc_host *host){ host->ios.clock = 0; host->ios.vdd = 0; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host);}/* * 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); BUG_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);}/* * Remove the current bus handler from a host. Assumes that there are * no interesting cards left, so the bus is powered down. */void mmc_detach_bus(struct mmc_host *host){ unsigned long flags; BUG_ON(!host); BUG_ON(!host->claimed); BUG_ON(!host->bus_ops); spin_lock_irqsave(&host->lock, flags); host->bus_dead = 1; spin_unlock_irqrestore(&host->lock, flags); mmc_power_off(host); mmc_bus_put(host);}/* * Cleanup when the last reference to the bus operator is dropped. */void __mmc_release_bus(struct mmc_host *host){ BUG_ON(!host); BUG_ON(host->bus_refs); BUG_ON(!host->bus_dead); host->bus_ops = NULL;}/** * mmc_detect_change - process change of state on a MMC socket * @host: host which changed state. * @delay: optional delay to wait before detection (jiffies) * * All we know is that card(s) have been inserted or removed * from the socket(s). We don't know which socket or cards. */void mmc_detect_change(struct mmc_host *host, unsigned long delay){ mmc_schedule_delayed_work(&host->detect, delay);}EXPORT_SYMBOL(mmc_detect_change);static void mmc_rescan(struct work_struct *work){ struct mmc_host *host = container_of(work, struct mmc_host, detect.work); u32 ocr; int err; mmc_bus_get(host); if (host->bus_ops == NULL) { /* * Only we can add a new handler, so it's safe to * release the lock here. */ mmc_bus_put(host); mmc_claim_host(host); mmc_power_up(host); mmc_go_idle(host); /* Detect SDIO cards */ err = io_send_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { if (mmc_attach_sdio(host, ocr)) mmc_power_off(host); } else { /* * If we fail to detect any SDIO cards then try * searching for SD cards. */ mmc_send_if_cond(host, host->ocr_avail); err = mmc_send_app_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { if (mmc_attach_sd(host, ocr)) mmc_power_off(host); } else { /* * If we fail to detect any SD cards then try * searching for MMC cards. */ err = mmc_send_op_cond(host, 0, &ocr); if (err == MMC_ERR_NONE) { if (mmc_attach_mmc(host, ocr)) mmc_power_off(host); } else { mmc_power_off(host); mmc_release_host(host); } } } } else { if (host->bus_ops->detect && !host->bus_dead) host->bus_ops->detect(host); mmc_bus_put(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_DELAYED_WORK(&host->detect, mmc_rescan); /* * 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_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;}EXPORT_SYMBOL(mmc_alloc_host);/** * mmc_add_host - initialise host hardware * @host: mmc host */int mmc_add_host(struct mmc_host *host){ int ret; ret = mmc_add_host_sysfs(host); if (ret == 0) { mmc_power_off(host); mmc_detect_change(host, 0); } return ret;}EXPORT_SYMBOL(mmc_add_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. */void mmc_remove_host(struct mmc_host *host){ mmc_flush_scheduled_work(); mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->remove) host->bus_ops->remove(host); mmc_claim_host(host); mmc_detach_bus(host); mmc_release_host(host); } mmc_bus_put(host); BUG_ON(host->card); mmc_power_off(host); mmc_remove_host_sysfs(host);}EXPORT_SYMBOL(mmc_remove_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){ mmc_free_host_sysfs(host);}EXPORT_SYMBOL(mmc_free_host);/** * mmc_suspend_host - suspend a host * @host: mmc host * @state: suspend mode (PM_SUSPEND_xxx) */int mmc_suspend_host(struct mmc_host *host, pm_message_t state){ mmc_flush_scheduled_work(); mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { if (host->bus_ops->suspend) host->bus_ops->suspend(host); if (!host->bus_ops->resume) { if (host->bus_ops->remove) host->bus_ops->remove(host); mmc_claim_host(host); mmc_detach_bus(host); mmc_release_host(host); } } mmc_bus_put(host); mmc_power_off(host); return 0;}EXPORT_SYMBOL(mmc_suspend_host);/** * mmc_resume_host - resume a previously suspended host * @host: mmc host */int mmc_resume_host(struct mmc_host *host){ mmc_bus_get(host); if (host->bus_ops && !host->bus_dead) { mmc_power_up(host); BUG_ON(!host->bus_ops->resume); host->bus_ops->resume(host); } mmc_bus_put(host); /* * We add a slight delay here so that resume can progress * in parallel. */ mmc_detect_change(host, 1); return 0;}EXPORT_SYMBOL(mmc_resume_host);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -