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

📄 mmc_core.c

📁 包含MMC协议,驱动源码. 在LINUX操作系统下通过.
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Core MMC driver functions * * Copyright 2002 Hewlett-Packard Company * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is * preserved in its entirety in all copies and derived works. * * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS * FITNESS FOR ANY PARTICULAR PURPOSE. * * Many thanks to Alessandro Rubini and Jonathan Corbet! * * Author:  Andrew Christian *          6 May 2002 *//* *	SD Cards specific functions implemented * * Copyright 2003 MontaVista Software Inc. * Author: MontaVista Software, Inc. *	   source@mvista.com * *  This program is free software; you can redistribute	 it and/or modify it *  under  the terms of	 the GNU General  Public License as published by the *  Free Software Foundation;  either version 2 of the	License, or (at your *  option) any later version. * *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT, *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *  You should have received a copy of the  GNU General Public License along *  with this program; if not, write  to the Free Software Foundation, Inc., *  675 Mass Ave, Cambridge, MA 02139, USA. *//* * Copyright 2004-2005 Motorola, Inc. All Rights Reserved. * Revision History:                    Modification     Changed by            Date             Description of Changes----------------   ------------       -------------------------Zhu Zhifu           05/27/2004         change for SDjiang Lili          07/04/2005         modify for support 2GB cardLi Xin              09/15/2005         for mass storage read/write no via fs*/#undef CONFIG_CEE#if defined(CONFIG_ARCH_OMAP) || defined(CONFIG_ARCH_MAINSTONE) || defined(CONFIG_ARCH_MX2ADS)#define CONFIG_CEE#endif#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/list.h>#include <linux/sysctl.h>#include <linux/pm.h>#ifdef CONFIG_USBD_ISP_BUS#include <linux/completion.h>#endif#include "mmc_core.h"#define STATE_CMD_ACTIVE   (1<<0)#define STATE_CMD_DONE     (1<<1)#define STATE_INSERT       (1<<2)#define STATE_EJECT        (1<<3)static struct mmc_dev          g_mmc_dev;static struct proc_dir_entry  *proc_mmc_dir;//#ifdef CONFIG_ARCH_EZX_E680int first_have_card = 0;int mmc_slot_enable = 1;//#endif#ifdef CONFIG_MMC_DEBUGint g_mmc_debug = CONFIG_MMC_DEBUG_VERBOSE;#elseint g_mmc_debug = 0;#endif//#ifdef CONFIG_ARCH_EZX_E680EXPORT_SYMBOL(mmc_slot_enable);EXPORT_SYMBOL(first_have_card);//#endifEXPORT_SYMBOL(g_mmc_debug);/************************************************************************** * Debugging functions **************************************************************************/static char * mmc_result_strings[] = {	"NO_RESPONSE",	"NO_ERROR",	"ERROR_OUT_OF_RANGE",	"ERROR_ADDRESS",	"ERROR_BLOCK_LEN",	"ERROR_ERASE_SEQ",	"ERROR_ERASE_PARAM",	"ERROR_WP_VIOLATION",	"ERROR_CARD_IS_LOCKED",	"ERROR_LOCK_UNLOCK_FAILED",	"ERROR_COM_CRC",	"ERROR_ILLEGAL_COMMAND",	"ERROR_CARD_ECC_FAILED",	"ERROR_CC",	"ERROR_GENERAL",	"ERROR_UNDERRUN",	"ERROR_OVERRUN",	"ERROR_CID_CSD_OVERWRITE",	"ERROR_STATE_MISMATCH",	"ERROR_HEADER_MISMATCH",	"ERROR_TIMEOUT",	"ERROR_CRC",	"ERROR_DRIVER_FAILURE",};char * mmc_result_to_string( int i ){	return mmc_result_strings[i+1];}static char * card_state_strings[] = {	"empty",	"idle",	"ready",	"ident",	"stby",	"tran",	"data",	"rcv",	"prg",	"dis",};static inline char * card_state_to_string( int i ){	return card_state_strings[i+1];}/************************************************************************** * Utility functions **************************************************************************/#define PARSE_U32(_buf,_index) \	(((u32)_buf[_index]) << 24) | (((u32)_buf[_index+1]) << 16) | \        (((u32)_buf[_index+2]) << 8) | ((u32)_buf[_index+3]);#define PARSE_U16(_buf,_index) \	(((u16)_buf[_index]) << 8) | ((u16)_buf[_index+1]);int mmc_unpack_csd( struct mmc_request *request, struct mmc_csd *csd ){	u8 *buf = request->response;    int num = 0;		if ( request->result ) return request->result;	csd->csd_structure      = (buf[1] & 0xc0) >> 6;	csd->spec_vers          = (buf[1] & 0x3c) >> 2;	csd->taac               = buf[2];	csd->nsac               = buf[3];	csd->tran_speed         = buf[4];	csd->ccc                = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4);	csd->read_bl_len        = buf[6] & 0x0f;    /* for support 2GB card*/	if ( csd->read_bl_len >= 10) 	{	     num = csd->read_bl_len - 9;	     csd->read_bl_len = 9;	}	csd->read_bl_partial    = (buf[7] & 0x80) ? 1 : 0;	csd->write_blk_misalign = (buf[7] & 0x40) ? 1 : 0;	csd->read_blk_misalign  = (buf[7] & 0x20) ? 1 : 0;	csd->dsr_imp            = (buf[7] & 0x10) ? 1 : 0;	csd->c_size             = ((((u16)buf[7]) & 0x03) << 10) | (((u16)buf[8]) << 2) | (((u16)buf[9]) & 0xc0) >> 6;	if (num)	{		csd->c_size = csd->c_size << num;	}			csd->vdd_r_curr_min     = (buf[9] & 0x38) >> 3;	csd->vdd_r_curr_max     = buf[9] & 0x07;	csd->vdd_w_curr_min     = (buf[10] & 0xe0) >> 5;	csd->vdd_w_curr_max     = (buf[10] & 0x1c) >> 2;	csd->c_size_mult        = ((buf[10] & 0x03) << 1) | ((buf[11] & 0x80) >> 7);	switch ( csd->csd_structure ) {	case CSD_STRUCT_VER_1_0:	case CSD_STRUCT_VER_1_1:		csd->erase.v22.sector_size    = (buf[11] & 0x7c) >> 2;		csd->erase.v22.erase_grp_size = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);		break;	case CSD_STRUCT_VER_1_2:	default:		csd->erase.v31.erase_grp_size = (buf[11] & 0x7c) >> 2;		csd->erase.v31.erase_grp_mult = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);		break;	}	csd->wp_grp_size        = buf[12] & 0x1f;	csd->wp_grp_enable      = (buf[13] & 0x80) ? 1 : 0;	csd->default_ecc        = (buf[13] & 0x60) >> 5;	csd->r2w_factor         = (buf[13] & 0x1c) >> 2;	csd->write_bl_len       = ((buf[13] & 0x03) << 2) | ((buf[14] & 0xc0) >> 6);	if (csd->write_bl_len >= 10)	    csd->write_bl_len = 9;	csd->write_bl_partial   = (buf[14] & 0x20) ? 1 : 0;	csd->file_format_grp    = (buf[15] & 0x80) ? 1 : 0;	csd->copy               = (buf[15] & 0x40) ? 1 : 0;	csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0;	csd->tmp_write_protect  = (buf[15] & 0x10) ? 1 : 0;	csd->file_format        = (buf[15] & 0x0c) >> 2;	csd->ecc                = buf[15] & 0x03;	DEBUG(2,"  csd_structure=%d  spec_vers=%d  taac=%02x  nsac=%02x  tran_speed=%02x\n"	      "  ccc=%04x  read_bl_len=%d  read_bl_partial=%d  write_blk_misalign=%d\n"	      "  read_blk_misalign=%d  dsr_imp=%d  c_size=%d  vdd_r_curr_min=%d\n"	      "  vdd_r_curr_max=%d  vdd_w_curr_min=%d  vdd_w_curr_max=%d  c_size_mult=%d\n"	      "  wp_grp_size=%d  wp_grp_enable=%d  default_ecc=%d  r2w_factor=%d\n"	      "  write_bl_len=%d  write_bl_partial=%d  file_format_grp=%d  copy=%d\n"	      "  perm_write_protect=%d  tmp_write_protect=%d  file_format=%d  ecc=%d\n",	      csd->csd_structure, csd->spec_vers, 	      csd->taac, csd->nsac, csd->tran_speed,	      csd->ccc, csd->read_bl_len, 	      csd->read_bl_partial, csd->write_blk_misalign,	      csd->read_blk_misalign, csd->dsr_imp, 	      csd->c_size, csd->vdd_r_curr_min,	      csd->vdd_r_curr_max, csd->vdd_w_curr_min, 	      csd->vdd_w_curr_max, csd->c_size_mult,	      csd->wp_grp_size, csd->wp_grp_enable,	      csd->default_ecc, csd->r2w_factor, 	      csd->write_bl_len, csd->write_bl_partial,	      csd->file_format_grp, csd->copy, 	      csd->perm_write_protect, csd->tmp_write_protect,	      csd->file_format, csd->ecc);	switch (csd->csd_structure) {	case CSD_STRUCT_VER_1_0:	case CSD_STRUCT_VER_1_1:		DEBUG(2," V22 sector_size=%d erase_grp_size=%d\n", 		      csd->erase.v22.sector_size, 		      csd->erase.v22.erase_grp_size);		break;	case CSD_STRUCT_VER_1_2:	default:		DEBUG(2," V31 erase_grp_size=%d erase_grp_mult=%d\n", 		      csd->erase.v31.erase_grp_size,		      csd->erase.v31.erase_grp_mult);		break;			}	if ( buf[0] != 0x3f )  return MMC_ERROR_HEADER_MISMATCH;	return 0;}int mmc_unpack_r1( struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state ){	u8 *buf = request->response;	if ( request->result )        return request->result;	r1->cmd    = buf[0];	r1->status = PARSE_U32(buf,1);	DEBUG(2," cmd=%d status=%08x\n", r1->cmd, r1->status);	if (R1_STATUS(r1->status)) {		if ( r1->status & R1_OUT_OF_RANGE )       return MMC_ERROR_OUT_OF_RANGE;		if ( r1->status & R1_ADDRESS_ERROR )      return MMC_ERROR_ADDRESS;		if ( r1->status & R1_BLOCK_LEN_ERROR )    return MMC_ERROR_BLOCK_LEN;		if ( r1->status & R1_ERASE_SEQ_ERROR )    return MMC_ERROR_ERASE_SEQ;		if ( r1->status & R1_ERASE_PARAM )        return MMC_ERROR_ERASE_PARAM;		if ( r1->status & R1_WP_VIOLATION )       return MMC_ERROR_WP_VIOLATION;		//if ( r1->status & R1_CARD_IS_LOCKED )     return MMC_ERROR_CARD_IS_LOCKED;		if ( r1->status & R1_LOCK_UNLOCK_FAILED ) return MMC_ERROR_LOCK_UNLOCK_FAILED;		if ( r1->status & R1_COM_CRC_ERROR )      return MMC_ERROR_COM_CRC;		if ( r1->status & R1_ILLEGAL_COMMAND )    return MMC_ERROR_ILLEGAL_COMMAND;		if ( r1->status & R1_CARD_ECC_FAILED )    return MMC_ERROR_CARD_ECC_FAILED;		if ( r1->status & R1_CC_ERROR )           return MMC_ERROR_CC;		if ( r1->status & R1_ERROR )              return MMC_ERROR_GENERAL;		if ( r1->status & R1_UNDERRUN )           return MMC_ERROR_UNDERRUN;		if ( r1->status & R1_OVERRUN )            return MMC_ERROR_OVERRUN;		if ( r1->status & R1_CID_CSD_OVERWRITE )  return MMC_ERROR_CID_CSD_OVERWRITE;	}	if ( buf[0] != request->cmd ) return MMC_ERROR_HEADER_MISMATCH;	/* This should be last - it's the least dangerous error */	if ( R1_CURRENT_STATE(r1->status) != state ) return MMC_ERROR_STATE_MISMATCH;	return 0;}int mmc_unpack_scr(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, u32 *scr){        u8 *buf = request->response;	if ( request->result )        return request->result;                *scr = PARSE_U32(buf, 5); /* Save SCR returned by the SD Card */        return mmc_unpack_r1(request, r1, state);        }int mmc_unpack_r6(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, int *rca){	u8 *buf = request->response;	if ( request->result )        return request->result;                *rca = PARSE_U16(buf,1);  /* Save RCA returned by the SD Card */                *(buf+1) = 0;        *(buf+2) = 0;                return mmc_unpack_r1(request, r1, state);}   int mmc_unpack_cid( struct mmc_request *request, struct mmc_cid *cid ){	u8 *buf = request->response;	int i;	if ( request->result ) return request->result;	cid->mid = buf[1];	cid->oid = PARSE_U16(buf,2);	for ( i = 0 ; i < 6 ; i++ )		cid->pnm[i] = buf[4+i];	cid->pnm[6] = 0;	cid->prv = buf[10];	cid->psn = PARSE_U32(buf,11);	cid->mdt = buf[15];		DEBUG(2," mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d\n",	      cid->mid, cid->oid, cid->pnm, 	      (cid->prv>>4), (cid->prv&0xf), 	      cid->psn, (cid->mdt>>4), (cid->mdt&0xf)+1997);	if ( buf[0] != 0x3f )  return MMC_ERROR_HEADER_MISMATCH;      	return 0;}int mmc_unpack_r3( struct mmc_request *request, struct mmc_response_r3 *r3 ){	u8 *buf = request->response;	if ( request->result ) return request->result;	r3->ocr = PARSE_U32(buf,1);	DEBUG(2," ocr=%08x\n", r3->ocr);	if ( buf[0] != 0x3f )  return MMC_ERROR_HEADER_MISMATCH;	return 0;}/**************************************************************************/#define KBPS 1#define MBPS 1000static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 };static u32 ts_mul[] = { 0,    1000, 1200, 1300, 1500, 2000, 2500, 3000, 			3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 };u32 mmc_tran_speed( u8 ts ){	u32 rate = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3];	if ( rate <= 0 ) {		DEBUG(0, ": error - unrecognized speed 0x%02x\n", ts);		return 1;	}	return rate;}/**************************************************************************/void mmc_send_cmd( struct mmc_dev *dev, int cmd, u32 arg, 		   u16 nob, u16 block_len, enum mmc_rsp_t rtype ){	dev->request.cmd       = cmd;	dev->request.arg       = arg;	dev->request.rtype     = rtype;	dev->request.nob       = nob;	dev->request.block_len = block_len;	dev->request.buffer    = NULL;	dev->request.cnt       = nob * block_len;	if ( nob && dev->io_request )		dev->request.buffer = dev->io_request->buffer;	dev->state  |= STATE_CMD_ACTIVE;	dev->sdrive->send_cmd(&dev->request);}void mmc_finish_io_request( struct mmc_dev *dev, int result ){	struct mmc_io_request *t = dev->io_request;	struct mmc_slot *slot = dev->slot + t->id;	dev->io_request = NULL;     // Remove the old request (the media driver may requeue)	switch( t->cmd ){	case MMC_IO_READ:	case MMC_IO_WRITE:		if ( slot->media_driver )			slot->media_driver->io_request_done( t, result );		break;	default:		break;	}	if (t->done) 		t->done(t);	/* process pending request */	if (dev->next_io_request) {		dev->io_request = dev->next_io_request;		dev->next_io_request = NULL;		tasklet_schedule(&dev->task);	}}/* Only call this when there is no pending request - it unloads the media driver */int mmc_check_eject( struct mmc_dev *dev ){	unsigned long   flags;	int             state;	int             i;	DEBUG(2," dev state=%x\n", dev->state);	local_irq_save(flags);	state = dev->state;	dev->state = state & ~STATE_EJECT;	local_irq_restore(flags);	if ( !(state & STATE_EJECT) )		return 0;	for ( i = 0 ; i < dev->num_slots ; i++ ) {		struct mmc_slot *slot = dev->slot + i;		if ( slot->flags & MMC_SLOT_FLAG_EJECT ) {			slot->state = CARD_STATE_EMPTY;			if ( slot->media_driver ) {				slot->media_driver->unload( slot );				slot->media_driver = NULL;			}			slot->flags &= ~MMC_SLOT_FLAG_EJECT;			run_sbin_mmc_hotplug(dev,i,0);		}	}	return 1;}int mmc_check_insert( struct mmc_dev *dev ){	unsigned long   flags;	int             state;	int             i;	int             card_count = 0;	DEBUG(2," dev state=%x\n", dev->state);	local_irq_save(flags);	state = dev->state;	dev->state = state & ~STATE_INSERT;	local_irq_restore(flags);

⌨️ 快捷键说明

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