core.c
来自「linux 内核源代码」· C语言 代码 · 共 829 行 · 第 1/2 页
C
829 行
*/void mmc_set_bus_width(struct mmc_host *host, unsigned int width){ host->ios.bus_width = width; mmc_set_ios(host);}/* * Mask off any voltages we don't support and select * the lowest voltage */u32 mmc_select_voltage(struct mmc_host *host, u32 ocr){ int bit; ocr &= host->ocr_avail; bit = ffs(ocr); if (bit) { bit -= 1; ocr &= 3 << bit; host->ios.vdd = bit; mmc_set_ios(host); } else { ocr = 0; } return ocr;}/* * Select timing parameters for host. */void mmc_set_timing(struct mmc_host *host, unsigned int timing){ host->ios.timing = timing; mmc_set_ios(host);}/* * 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; if (mmc_host_is_spi(host)) { host->ios.chip_select = MMC_CS_HIGH; host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; } else { host->ios.chip_select = MMC_CS_DONTCARE; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; } 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); /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. */ mmc_delay(2); host->ios.clock = host->f_min; host->ios.power_mode = MMC_POWER_ON; mmc_set_ios(host); /* * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ mmc_delay(2);}static void mmc_power_off(struct mmc_host *host){ host->ios.clock = 0; host->ios.vdd = 0; if (!mmc_host_is_spi(host)) { 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);}/* * 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;}/* * Increase reference count of bus operator */static inline void mmc_bus_get(struct mmc_host *host){ unsigned long flags; spin_lock_irqsave(&host->lock, flags); host->bus_refs++; spin_unlock_irqrestore(&host->lock, flags);}/* * Decrease reference count of bus operator and free it if * it is the last reference. */static inline void mmc_bus_put(struct mmc_host *host){ unsigned long flags; spin_lock_irqsave(&host->lock, flags); host->bus_refs--; if ((host->bus_refs == 0) && host->bus_ops) __mmc_release_bus(host); spin_unlock_irqrestore(&host->lock, flags);}/* * 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);}/* * 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); WARN_ON(!host->claimed); WARN_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);}/** * mmc_detect_change - process change of state on a MMC socket * @host: host which changed state. * @delay: optional delay to wait before detection (jiffies) * * MMC drivers should call this when they detect a card has been * inserted or removed. The MMC layer will confirm that any * present card is still functional, and initialize any newly * inserted. */void mmc_detect_change(struct mmc_host *host, unsigned long delay){#ifdef CONFIG_MMC_DEBUG unsigned long flags; spin_lock_irqsave(&host->lock, flags); WARN_ON(host->removed); spin_unlock_irqrestore(&host->lock, flags);#endif mmc_schedule_delayed_work(&host->detect, delay);}EXPORT_SYMBOL(mmc_detect_change);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); mmc_send_if_cond(host, host->ocr_avail); /* * First we search for SDIO... */ err = mmc_send_io_op_cond(host, 0, &ocr); if (!err) { if (mmc_attach_sdio(host, ocr)) mmc_power_off(host); return; } /* * ...then normal SD... */ err = mmc_send_app_op_cond(host, 0, &ocr); if (!err) { if (mmc_attach_sd(host, ocr)) mmc_power_off(host); return; } /* * ...and finally MMC. */ err = mmc_send_op_cond(host, 0, &ocr); if (!err) { if (mmc_attach_mmc(host, ocr)) mmc_power_off(host); return; } mmc_release_host(host); mmc_power_off(host); } else { if (host->bus_ops->detect && !host->bus_dead) host->bus_ops->detect(host); mmc_bus_put(host); }}void mmc_start_host(struct mmc_host *host){ mmc_power_off(host); mmc_detect_change(host, 0);}void mmc_stop_host(struct mmc_host *host){#ifdef CONFIG_MMC_DEBUG unsigned long flags; spin_lock_irqsave(&host->lock, flags); host->removed = 1; spin_unlock_irqrestore(&host->lock, flags);#endif 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);}#ifdef CONFIG_PM/** * 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);#endifstatic int __init mmc_init(void){ int ret; workqueue = create_singlethread_workqueue("kmmcd"); if (!workqueue) return -ENOMEM; ret = mmc_register_bus(); if (ret) goto destroy_workqueue; ret = mmc_register_host_class(); if (ret) goto unregister_bus; ret = sdio_register_bus(); if (ret) goto unregister_host_class; return 0;unregister_host_class: mmc_unregister_host_class();unregister_bus: mmc_unregister_bus();destroy_workqueue: destroy_workqueue(workqueue); return ret;}static void __exit mmc_exit(void){ sdio_unregister_bus(); mmc_unregister_host_class(); mmc_unregister_bus(); destroy_workqueue(workqueue);}subsys_initcall(mmc_init);module_exit(mmc_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?