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

📄 mmc.c

📁 dm320平台的LINUX mmc和sd卡驱动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/drivers/mmc/mmc.c * *  Copyright (C) 2003-2004 Russell King, All Rights Reserved. *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. *  SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/interrupt.h>#include <linux/completion.h>#include <linux/device.h>#include <linux/delay.h>#include <linux/pagemap.h>#include <linux/err.h>#include <asm/scatterlist.h>#include <linux/scatterlist.h>#include <linux/mmc/card.h>#include <linux/mmc/host.h>#include <linux/mmc/protocol.h>#include "mmc.h"#include "mmc_debug.h"MODULE_LICENSE("INGENIENT");#ifdef CONFIG_MMC_DEBUG#define DBG(x...)	mmc_debug_msg(KERN_DEBUG x)#else#define DBG(x...)	do { } while (0)#endif#define CMD_RETRIES	3static int action = 1;/* 0:add  1:remove*/static int cardtype = 0; /* 0:sd 1:mmc*//* * OCR Bit positions to 10s of Vdd mV. */static const unsigned short mmc_ocr_bit_to_vdd[] = {	150,	155,	160,	165,	170,	180,	190,	200,	210,	220,	230,	240,	250,	260,	270,	280,	290,	300,	310,	320,	330,	340,	350,	360};static const unsigned int tran_exp[] = {	10000,		100000,		1000000,	10000000,	0,		0,		0,		0};static const unsigned char tran_mant[] = {	0,	10,	12,	13,	15,	20,	25,	30,	35,	40,	45,	50,	55,	60,	70,	80,};static const unsigned int tacc_exp[] = {	1,	10,	100,	1000,	10000,	100000,	1000000, 10000000,};static const unsigned int tacc_mant[] = {	0,	10,	12,	13,	15,	20,	25,	30,	35,	40,	45,	50,	55,	60,	70,	80,}; /** *	mmc_request_done - finish processing an MMC command *	@host: MMC host which completed command *	@mrq: MMC request which completed * *	MMC drivers should call this function when they have completed *	their processing of a command.  This should be called before the *	data part of the command has completed. */                                            void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq){	struct mmc_command *cmd = mrq->cmd;	int err = mrq->cmd->error;	if (err && cmd->retries) {		mmc_debug_msg ("%s %d cmd->retries : %d ERR : %d \n",__FUNCTION__,__LINE__,cmd->retries,err);		cmd->retries--;		cmd->error = 0;		host->ops->request(host, mrq);	} else if (mrq->done) {		mmc_debug_msg ("%s %d cmd->retries : %d ERR : %d \n",__FUNCTION__,__LINE__,cmd->retries,err);		mrq->done(mrq);	}}EXPORT_SYMBOL(mmc_request_done);/** *	mmc_start_request - start a command on a host *	@host: MMC host to start command on *	@mrq: MMC request to start * *	Queue a command on the specified host.  We expect the *	caller to be holding the host lock with interrupts disabled. */voidmmc_start_request(struct mmc_host *host, struct mmc_request *mrq){	WARN_ON(host->card_busy == NULL);		mrq->cmd->error = 0;	mrq->cmd->mrq = mrq;	if (mrq->data) {			mmc_debug_msg("%s in line %d\n",__FUNCTION__,__LINE__);		mrq->cmd->data = mrq->data;		mrq->data->error = 0;		mrq->data->mrq = mrq;		if (mrq->stop) {			mrq->data->stop = mrq->stop;			mrq->stop->error = 0;			mrq->stop->mrq = mrq;		}	}	host->ops->request(host, mrq);}EXPORT_SYMBOL(mmc_start_request);static void mmc_wait_done(struct mmc_request *mrq){		complete(mrq->done_data);}int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq){	DECLARE_COMPLETION(complete);	mrq->done_data = &complete;	mrq->done = mmc_wait_done;			mmc_start_request(host, mrq);	wait_for_completion(&complete);		return 0;}EXPORT_SYMBOL(mmc_wait_for_req);int mmc_wait_for_read_data(struct mmc_host *host, struct mmc_request *mrq){	host->readdata(host,mrq);	return 0;}EXPORT_SYMBOL(mmc_wait_for_read_data);int mmc_wait_for_write_data(struct mmc_host *host, struct mmc_request *mrq){	host->writedata(host,mrq);	return 0;}EXPORT_SYMBOL(mmc_wait_for_write_data);/** *	mmc_wait_for_cmd - start a command and wait for completion *	@host: MMC host to start command *	@cmd: MMC command to start *	@retries: maximum number of retries * *	Start a new MMC command for a host, and wait for the command *	to complete.  Return any error that occurred while the command *	was executing.  Do not attempt to parse the response. */int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries){	struct mmc_request mrq;	BUG_ON(host->card_busy == NULL);	memset(&mrq, 0, sizeof(struct mmc_request));	memset(cmd->resp, 0, sizeof(cmd->resp));	cmd->retries = retries;	mrq.cmd = cmd;	cmd->data = NULL;	mmc_wait_for_req(host, &mrq);	return cmd->error;}EXPORT_SYMBOL(mmc_wait_for_cmd);/** *	mmc_wait_for_app_cmd - start an application command and wait for 			       completion *	@host: MMC host to start command *	@rca: RCA to send MMC_APP_CMD to *	@cmd: MMC command to start *	@retries: maximum number of retries * *	Sends a MMC_APP_CMD, checks the card response, sends the command *	in the parameter and waits for it to complete. Return any error *	that occurred while the command was executing.  Do not attempt to *	parse the response. */int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,	struct mmc_command *cmd, int retries){	struct mmc_request mrq;	struct mmc_command appcmd;	int i, err;	BUG_ON(host->card_busy == NULL);	BUG_ON(retries < 0);	err = MMC_ERR_INVALID;	/*	 * We have to resend MMC_APP_CMD for each attempt so	 * we cannot use the retries field in mmc_command.	 */	for (i = 0;i <= retries;i++) {		memset(&mrq, 0, sizeof(struct mmc_request));		appcmd.opcode = MMC_APP_CMD;		appcmd.arg = rca << 16;		appcmd.flags = MMCSD_RSP1;		appcmd.retries = 0;		memset(appcmd.resp, 0, sizeof(appcmd.resp));		appcmd.data = NULL;		mrq.cmd = &appcmd;		appcmd.data = NULL;		mmc_wait_for_req(host, &mrq);		if (appcmd.error) {			mmc_debug_msg ("appcmd.error : %d in function  %s at line %d\n",appcmd.error,__FUNCTION__,__LINE__);			err = appcmd.error;			continue;		}				mmc_debug_msg ("appcmd : %p\n",&appcmd);		/* Check that card supported application commands */		if (!(appcmd.resp[6] & R1_APP_CMD ))//I m checking for if it can accept an application command			return MMC_ERR_FAILED;		memset(&mrq, 0, sizeof(struct mmc_request));		memset(cmd->resp, 0, sizeof(cmd->resp));		cmd->retries = 0;		mrq.cmd = cmd;		cmd->data = NULL;		mmc_wait_for_req(host, &mrq);		err = cmd->error;		if (cmd->error == MMC_ERR_NONE)			break;	}	return err;}EXPORT_SYMBOL(mmc_wait_for_app_cmd);static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);/** *	__mmc_claim_host - exclusively claim a host *	@host: mmc host to claim *	@card: mmc card to claim host for * *	Claim a host for a set of operations.  If a valid card *	is passed and this wasn't the last card selected, select *	the card before returning. * *	Note: you should use mmc_card_claim_host or mmc_claim_host. */int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card){	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	int err = 0;	add_wait_queue(&host->wq, &wait);	spin_lock_irqsave(&host->lock, flags);	while (1) {		set_current_state(TASK_UNINTERRUPTIBLE);		if (host->card_busy == NULL)			break;		spin_unlock_irqrestore(&host->lock, flags);		schedule();		spin_lock_irqsave(&host->lock, flags);	}	set_current_state(TASK_RUNNING);	host->card_busy = card;	spin_unlock_irqrestore(&host->lock, flags);	remove_wait_queue(&host->wq, &wait);	if (card != (void *)-1) {		err = mmc_select_card(host, card);		if (err != MMC_ERR_NONE)			return err;	}	return err;}EXPORT_SYMBOL(__mmc_claim_host);/** *	mmc_release_host - release a host *	@host: mmc host to release * *	Release a MMC host, allowing others to claim the host *	for their operations. */void mmc_release_host(struct mmc_host *host){	unsigned long flags;	BUG_ON(host->card_busy == NULL);	spin_lock_irqsave(&host->lock, flags);	host->card_busy = NULL;	spin_unlock_irqrestore(&host->lock, flags);	wake_up(&host->wq);}EXPORT_SYMBOL(mmc_release_host);static int mmc_select_card(struct mmc_host *host, struct mmc_card *card){	int err;	struct mmc_command cmd;	BUG_ON(host->card_busy == NULL);	if (host->card_selected == card)		return MMC_ERR_NONE;	host->card_selected = card;		mmc_debug_msg ("%s %d %d\n",__FUNCTION__,__LINE__,card->rca );	cmd.opcode = MMC_SELECT_CARD;        cmd.arg = card->rca << 16;        cmd.flags = MMCSD_RSP1;	err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);	if (err != MMC_ERR_NONE)		return err;	/*	 * Default bus width is 1 bit.	 */	host->ios.bus_width = MMC_BUS_WIDTH_1;	/*	 * We can only change the bus width of the selected	 * card so therefore we have to put the handling	 * here.	 */	if (host->caps & MMC_CAP_4_BIT_DATA) {		/*		 * The card is in 1 bit mode by default so		 * we only need to change if it supports the		 * wider version.		 */		if (mmc_card_sd(card) &&			(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {			struct mmc_command cmd;			cmd.opcode = SD_APP_SET_BUS_WIDTH;			cmd.arg = SD_BUS_WIDTH_4;			cmd.flags = MMCSD_RSP1;			err = mmc_wait_for_app_cmd(host, card->rca, &cmd,				CMD_RETRIES);			if (err != MMC_ERR_NONE)				return err;			host->ios.bus_width = MMC_BUS_WIDTH_4;		}	}	host->ops->set_ios(host, &host->ios);	return MMC_ERR_NONE;}/* * Ensure that no card is selected. */static void mmc_deselect_cards(struct mmc_host *host){	struct mmc_command cmd;	if (host->card_selected) {		host->card_selected = NULL;		cmd.opcode = MMC_SELECT_CARD;		cmd.arg = 0;		//cmd.flags = MMC_RSP_NONE;		cmd.flags = MMCSD_RSP1;		mmc_wait_for_cmd(host, &cmd, 0);	}}static inline void mmc_delay(unsigned int ms){	if (ms < HZ / 1000) {		yield();		mdelay(ms);	} else {		//msleep_interruptible (ms);	}}/* * Mask off any voltages we don't support and select * the lowest voltage */static 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;		ocr = 0xFC << bit;		host->ios.vdd = bit;		host->ops->set_ios(host, &host->ios);	} else {		ocr = 0;	}	return ocr;}#define UNSTUFF_BITS(resp,start,size) stuff_bits(resp,start,size)int stuff_bits (u16 * resp,int start,int size)        {                u16 __size = size;                u16 __mask = (__size < 16 ? 1 << __size : 0) - 1;                int __off = ((start) / 16);                int __shft = (start) & 15;                u16 __res = 0;		__res = resp [__off] >> __shft;                if (__size + __shft > 16){                        __res = resp [__off] >> __shft;                        __res |= resp[__off+1] << ((16 - __shft) % 16);                }	                return (__res & __mask);        }#if 0static unsigned short bitreverse (unsigned short unreversed);static unsigned short bitreverse (unsigned short unreversed){		unsigned short reversed = 0;	int i;	for (i=0;i<16;i++){		if (unreversed & (1 << i))			reversed |= (1 << (30 - (i+15)));	}			return reversed;}static unsigned int swap32 (unsigned int unswaped);static unsigned int swap32 (unsigned int unswaped){	u32 swaped = 0;	swaped = (unswaped << 16 | unswaped >> 16);	return swaped;}

⌨️ 快捷键说明

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