⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmc.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	kfree(ext_csd);	mmc_deselect_cards(host);}static void mmc_read_scrs(struct mmc_host *host){	int err;	struct mmc_card *card;	struct mmc_request mrq;	struct mmc_command cmd;	struct mmc_data data;	struct scatterlist sg;	list_for_each_entry(card, &host->cards, node) {		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))			continue;		if (!mmc_card_sd(card))			continue;		err = mmc_select_card(host, card);		if (err != MMC_ERR_NONE) {			mmc_card_set_dead(card);			continue;		}		memset(&cmd, 0, sizeof(struct mmc_command));		cmd.opcode = MMC_APP_CMD;		cmd.arg = card->rca << 16;		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;		err = mmc_wait_for_cmd(host, &cmd, 0);		if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {			mmc_card_set_dead(card);			continue;		}		memset(&cmd, 0, sizeof(struct mmc_command));		cmd.opcode = SD_APP_SEND_SCR;		cmd.arg = 0;		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;		memset(&data, 0, sizeof(struct mmc_data));		mmc_set_data_timeout(&data, card, 0);		data.blksz = 1 << 3;		data.blocks = 1;		data.flags = MMC_DATA_READ;		data.sg = &sg;		data.sg_len = 1;		memset(&mrq, 0, sizeof(struct mmc_request));		mrq.cmd = &cmd;		mrq.data = &data;		sg_init_one(&sg, (u8*)card->raw_scr, 8);		mmc_wait_for_req(host, &mrq);		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {			mmc_card_set_dead(card);			continue;		}		card->raw_scr[0] = ntohl(card->raw_scr[0]);		card->raw_scr[1] = ntohl(card->raw_scr[1]);		mmc_decode_scr(card);	}	mmc_deselect_cards(host);}static void mmc_read_switch_caps(struct mmc_host *host){	int err;	struct mmc_card *card;	struct mmc_request mrq;	struct mmc_command cmd;	struct mmc_data data;	unsigned char *status;	struct scatterlist sg;	status = kmalloc(64, GFP_KERNEL);	if (!status) {		printk(KERN_WARNING "%s: Unable to allocate buffer for "			"reading switch capabilities.\n",			mmc_hostname(host));		return;	}	list_for_each_entry(card, &host->cards, node) {		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))			continue;		if (!mmc_card_sd(card))			continue;		if (card->scr.sda_vsn < SCR_SPEC_VER_1)			continue;		err = mmc_select_card(host, card);		if (err != MMC_ERR_NONE) {			mmc_card_set_dead(card);			continue;		}		memset(&cmd, 0, sizeof(struct mmc_command));		cmd.opcode = SD_SWITCH;		cmd.arg = 0x00FFFFF1;		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;		memset(&data, 0, sizeof(struct mmc_data));		mmc_set_data_timeout(&data, card, 0);		data.blksz = 64;		data.blocks = 1;		data.flags = MMC_DATA_READ;		data.sg = &sg;		data.sg_len = 1;		memset(&mrq, 0, sizeof(struct mmc_request));		mrq.cmd = &cmd;		mrq.data = &data;		sg_init_one(&sg, status, 64);		mmc_wait_for_req(host, &mrq);		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {			mmc_card_set_dead(card);			continue;		}		if (status[13] & 0x02)			card->sw_caps.hs_max_dtr = 50000000;		memset(&cmd, 0, sizeof(struct mmc_command));		cmd.opcode = SD_SWITCH;		cmd.arg = 0x80FFFFF1;		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;		memset(&data, 0, sizeof(struct mmc_data));		mmc_set_data_timeout(&data, card, 0);		data.blksz = 64;		data.blocks = 1;		data.flags = MMC_DATA_READ;		data.sg = &sg;		data.sg_len = 1;		memset(&mrq, 0, sizeof(struct mmc_request));		mrq.cmd = &cmd;		mrq.data = &data;		sg_init_one(&sg, status, 64);		mmc_wait_for_req(host, &mrq);		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {			mmc_card_set_dead(card);			continue;		}		if ((status[16] & 0xF) != 1) {			printk(KERN_WARNING "%s: Problem switching card "				"into high-speed mode!\n",				mmc_hostname(host));			continue;		}		mmc_card_set_highspeed(card);	}	kfree(status);	mmc_deselect_cards(host);}static unsigned int mmc_calculate_clock(struct mmc_host *host){	struct mmc_card *card;	unsigned int max_dtr = host->f_max;	list_for_each_entry(card, &host->cards, node)		if (!mmc_card_dead(card)) {			if (mmc_card_highspeed(card) && mmc_card_sd(card)) {				if (max_dtr > card->sw_caps.hs_max_dtr)					max_dtr = card->sw_caps.hs_max_dtr;			} else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) {				if (max_dtr > card->ext_csd.hs_max_dtr)					max_dtr = card->ext_csd.hs_max_dtr;			} else if (max_dtr > card->csd.max_dtr) {				max_dtr = card->csd.max_dtr;			}		}	pr_debug("%s: selected %d.%03dMHz transfer rate\n",		 mmc_hostname(host),		 max_dtr / 1000000, (max_dtr / 1000) % 1000);	return max_dtr;}/* * Check whether cards we already know about are still present. * We do this by requesting status, and checking whether a card * responds. * * A request for status does not cause a state change in data * transfer mode. */static void mmc_check_cards(struct mmc_host *host){	struct list_head *l, *n;	mmc_deselect_cards(host);	list_for_each_safe(l, n, &host->cards) {		struct mmc_card *card = mmc_list_to_card(l);		struct mmc_command cmd;		int err;		cmd.opcode = MMC_SEND_STATUS;		cmd.arg = card->rca << 16;		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);		if (err == MMC_ERR_NONE)			continue;		mmc_card_set_dead(card);	}}static void mmc_setup(struct mmc_host *host){	if (host->ios.power_mode != MMC_POWER_ON) {		int err;		u32 ocr;		host->mode = MMC_MODE_SD;		mmc_power_up(host);		mmc_idle_cards(host);		err = mmc_send_app_op_cond(host, 0, &ocr);		/*		 * If we fail to detect any SD cards then try		 * searching for MMC cards.		 */		if (err != MMC_ERR_NONE) {			host->mode = MMC_MODE_MMC;			err = mmc_send_op_cond(host, 0, &ocr);			if (err != MMC_ERR_NONE)				return;		}		host->ocr = mmc_select_voltage(host, ocr);		/*		 * Since we're changing the OCR value, we seem to		 * need to tell some cards to go back to the idle		 * state.  We wait 1ms to give cards time to		 * respond.		 */		if (host->ocr)			mmc_idle_cards(host);	} else {		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;		host->ios.clock = host->f_min;		mmc_set_ios(host);		/*		 * We should remember the OCR mask from the existing		 * cards, and detect the new cards OCR mask, combine		 * the two and re-select the VDD.  However, if we do		 * change VDD, we should do an idle, and then do a		 * full re-initialisation.  We would need to notify		 * drivers so that they can re-setup the cards as		 * well, while keeping their queues at bay.		 *		 * For the moment, we take the easy way out - if the		 * new cards don't like our currently selected VDD,		 * they drop off the bus.		 */	}	if (host->ocr == 0)		return;	/*	 * Send the selected OCR multiple times... until the cards	 * all get the idea that they should be ready for CMD2.	 * (My SanDisk card seems to need this.)	 */	if (host->mode == MMC_MODE_SD)		mmc_send_app_op_cond(host, host->ocr, NULL);	else		mmc_send_op_cond(host, host->ocr, NULL);	mmc_discover_cards(host);	/*	 * Ok, now switch to push-pull mode.	 */	host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;	mmc_set_ios(host);	mmc_read_csds(host);	if (host->mode == MMC_MODE_SD) {		mmc_read_scrs(host);		mmc_read_switch_caps(host);	} else		mmc_process_ext_csds(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) * *	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);	struct list_head *l, *n;	unsigned char power_mode;	mmc_claim_host(host);	/*	 * Check for removed cards and newly inserted ones. We check for	 * removed cards first so we can intelligently re-select the VDD.	 */	power_mode = host->ios.power_mode;	if (power_mode == MMC_POWER_ON)		mmc_check_cards(host);	mmc_setup(host);	/*	 * Some broken cards process CMD1 even in stand-by state. There is	 * no reply, but an ILLEGAL_COMMAND error is cached and returned	 * after next command. We poll for card status here to clear any	 * possibly pending error.	 */	if (power_mode == MMC_POWER_ON)		mmc_check_cards(host);	if (!list_empty(&host->cards)) {		/*		 * (Re-)calculate the fastest clock rate which the		 * attached cards and the host support.		 */		host->ios.clock = mmc_calculate_clock(host);		mmc_set_ios(host);	}	mmc_release_host(host);	list_for_each_safe(l, n, &host->cards) {		struct mmc_card *card = mmc_list_to_card(l);		/*		 * If this is a new and good card, register it.		 */		if (!mmc_card_present(card) && !mmc_card_dead(card)) {			if (mmc_register_card(card))				mmc_card_set_dead(card);			else				mmc_card_set_present(card);		}		/*		 * If this card is dead, destroy it.		 */		if (mmc_card_dead(card)) {			list_del(&card->node);			mmc_remove_card(card);		}	}	/*	 * If we discover that there are no cards on the	 * bus, turn off the clock and power down.	 */	if (list_empty(&host->cards))		mmc_power_off(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_LIST_HEAD(&host->cards);		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_sectors = 1 << (PAGE_CACHE_SHIFT - 9);		host->max_seg_size = PAGE_CACHE_SIZE;	}	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){	struct list_head *l, *n;	list_for_each_safe(l, n, &host->cards) {		struct mmc_card *card = mmc_list_to_card(l);		mmc_remove_card(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_flush_scheduled_work();	mmc_free_host_sysfs(host);}EXPORT_SYMBOL(mmc_free_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_claim_host(host);	mmc_deselect_cards(host);	mmc_power_off(host);	mmc_release_host(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_rescan(&host->detect.work);	return 0;}EXPORT_SYMBOL(mmc_resume_host);#endifMODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -