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 + -
显示快捷键?