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

📄 mmc.c

📁 嵌入式Linux下SD卡的驱动 驱动主要以三星2410板设计的
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Allocate a new MMC card, and assign a unique RCA. */static struct mmc_card *mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, u8 sd, unsigned int *frca){	struct mmc_card *card, *c;	unsigned int rca = *frca;	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);	if (!card)		return ERR_PTR(-ENOMEM);	mmc_init_card(card, host);	memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid));	card->sd = sd; again:	list_for_each_entry(c, &host->cards, node)		if (c->rca == rca) {			rca++;			goto again;		}	card->rca = rca;	*frca = rca;	return card;}/* * Tell attached cards to go to IDLE state */static void mmc_idle_cards(struct mmc_host *host){	struct mmc_command cmd;	struct mmc_card *card;	cmd.opcode = MMC_GO_IDLE_STATE;	cmd.arg = 0;	cmd.flags = MMC_RSP_NONE;	mmc_wait_for_cmd(host, &cmd, 0);	//MMC_GO_IDLE_STATE resets all cards to bus width 1	list_for_each_entry(card, &host->cards, node) {		card->bus_width=1;	}	mmc_delay(100);}int sd_set_bus_width(struct mmc_host *host, u16 rca, u32 bus_width){	struct mmc_command cmd;	int err;	cmd.opcode = MMC_ACMD_SD_SET_BUS_WIDTH;	cmd.flags  = MMC_RSP_R1;	switch(bus_width) {		case 1:	 cmd.arg = 00; break;		case 4:	 cmd.arg = 10; break;		default: return -EINVAL;	}	err = mmc_wait_for_acmd(host, rca, &cmd, 3);	if(err == MMC_ERR_TIMEOUT) {		printk(KERN_ERR "MMC: sd_set_bus_width timed out.\n");	} else if(err == MMC_ERR_BADCRC) {		printk(KERN_ERR "MMC: sd_set_bus_width yielded crc error.\n");	} else {		DBG("MMC: sd_app_op_cond done.\n");	}	return err;}EXPORT_SYMBOL(sd_set_bus_width);static int sd_app_op_cond(struct mmc_host *host, u16 rca, u32 parameter, u32 *response){	struct mmc_command cmd;	int err;	int retries = 10;	cmd.opcode = MMC_ACMD_SD_APP_OP_COND;	cmd.arg = parameter;	cmd.flags = MMC_RSP_SHORT;	DBG("MMC: sd_app_op_cond to %08x\n",parameter);	while(retries--) {		err = mmc_wait_for_acmd(host, 0, &cmd, 0);		if(0 == (cmd.resp[0] & MMC_CARD_BUSY)) {			err=MMC_ERR_BUSY;			printk(KERN_ERR "MMC: sd_app_op_cond: at least one card is busy - trying again.\n");			mmc_delay(10);			//mmc_delay(20);			continue;		}		if(err == MMC_ERR_NONE) {			if(response)*response = cmd.resp[0];			break;		}	}	if(err == MMC_ERR_TIMEOUT) {		printk(KERN_WARNING "MMC: sd_app_op_cond timed out. Probably no SD-Card here.\n");	} else if(err == MMC_ERR_BUSY) {		printk(KERN_ERR "MMC: sd_app_op_cond locked busy. Probably have broken SD-Card.\n");	} else {		DBG("MMC: sd_app_op_cond done. Results are: 0x%08x.\n",cmd.resp[0]);	}	return err;}/* * Apply power to the MMC stack. */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.power_mode = MMC_POWER_UP;	host->ops->set_ios(host, &host->ios);	mmc_delay(1);	//mmc_delay(5);	host->ios.clock = host->f_min;	host->ios.power_mode = MMC_POWER_ON;	host->ops->set_ios(host, &host->ios);	mmc_delay(2);	//mmc_delay(5);}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.power_mode = MMC_POWER_OFF;	host->ops->set_ios(host, &host->ios);}static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr){	struct mmc_command cmd;	int i, err = 0;	cmd.opcode = MMC_SEND_OP_COND;	cmd.arg = ocr;	cmd.flags = MMC_RSP_R3;	for (i = 100; i; i--) {		err = mmc_wait_for_cmd(host, &cmd, 0);		if (err != MMC_ERR_NONE)			break;		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)			break;		err = MMC_ERR_TIMEOUT;		mmc_delay(10);	}	if (rocr)		*rocr = cmd.resp[0];	return err;}/* * Discover cards by requesting their CID.  If this command * times out, it is not an error; there are no further cards * to be discovered.  Add new cards to the list. * * Create a mmc_card entry for each discovered card, assigning * it an RCA, and save the raw CID for decoding later. */static void mmc_discover_cards(struct mmc_host *host, u8 sd){	struct mmc_card *card;	unsigned int first_rca = 1, err;	while (1) {		struct mmc_command cmd;		cmd.opcode = MMC_ALL_SEND_CID;		cmd.arg = 0;		cmd.flags = MMC_RSP_LONG; //HACK! CRC currently not implemented		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);		if (err == MMC_ERR_TIMEOUT) {			err = MMC_ERR_NONE;			break;		}		if (err != MMC_ERR_NONE) {			printk(KERN_ERR "%s: error requesting CID: %d\n",				mmc_hostname(host), err);			break;		}		card = mmc_find_card(host, cmd.resp);		if (!card) {			card = mmc_alloc_card(host, cmd.resp, sd, &first_rca);			if (IS_ERR(card)) {				err = PTR_ERR(card);				break;			}			list_add(&card->node, &host->cards);		}		card->state &= ~MMC_STATE_DEAD;		cmd.opcode = MMC_SET_RELATIVE_ADDR;		cmd.arg = card->rca << 16;		cmd.flags = MMC_RSP_R1;		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);		if (err != MMC_ERR_NONE)			mmc_card_set_dead(card);		//SD-Cards choose their adresses themselfes (yuck!)		if(card->sd) card->rca = (cmd.resp[0] >> 16);	}}static void mmc_read_csds(struct mmc_host *host){	struct mmc_card *card;	list_for_each_entry(card, &host->cards, node) {		struct mmc_command cmd;		int err;		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))			continue;		cmd.opcode = MMC_SEND_CSD;		cmd.arg = card->rca << 16;		cmd.flags = MMC_RSP_LONG; 	//HACK: No CRC check as s3c-Core is broken		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);		if (err != MMC_ERR_NONE) {			mmc_card_set_dead(card);			continue;		}		memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd));		mmc_decode_csd(card);		mmc_decode_cid(card);	}}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) && max_dtr > card->csd.max_dtr)			max_dtr = card->csd.max_dtr;	DBG("MMC: selected %d.%03dMHz transfer rate\n",	    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;		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){	mmc_power_up(host);	mmc_idle_cards(host);	// Wake and discover SD-Cards	sd_app_op_cond(host, 0, host->ocr_avail, NULL);	mmc_discover_cards(host, 1);	// Wake and discover MMC-Cards	mmc_send_op_cond(host, host->ocr_avail, NULL);	mmc_discover_cards(host, 0);	/*	 * switch to push-pull mode.	 */	host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;	host->ops->set_ios(host, &host->ios);	mmc_read_csds(host);}/** *	mmc_detect_change - process change of state on a MMC socket *	@host: host which changed state. * *	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){	schedule_work(&host->detect);}EXPORT_SYMBOL(mmc_detect_change);static void mmc_rescan(void *data){	struct mmc_host *host = data;	struct list_head *l, *n;    mmc_delay(500); // ghcstop fix: 20051226, 构 弊繁措肺 肋 登匙....	mmc_claim_host(host);	if (host->ios.power_mode == MMC_POWER_ON)		mmc_check_cards(host);	mmc_setup(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);		host->ops->set_ios(host, &host->ios);	}	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_WORK(&host->detect, mmc_rescan, host);		/*		 * 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);	}	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){	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_detect_change(host);	return 0;}EXPORT_SYMBOL(mmc_resume_host);#endifMODULE_LICENSE("GPL");

⌨️ 快捷键说明

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