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

📄 mmc_core.c.bak

📁 The sd/mmc driver for s3c2410, it is much better than the one from samsung
💻 BAK
📖 第 1 页 / 共 2 页
字号:
/* * 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 */#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>#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_MMC_DEBUGint g_mmc_debug = CONFIG_MMC_DEBUG_VERBOSE;EXPORT_SYMBOL(g_mmc_debug);#endif/************************************************************************** * 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;		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;	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;	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);	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;	MMC_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",		  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:		MMC_DEBUG(2,"V22 sector_size=%d erase_grp_size=%d", 		      csd->erase.v22.sector_size, 		      csd->erase.v22.erase_grp_size);		break;	case CSD_STRUCT_VER_1_2:	default:		MMC_DEBUG(2,"V31 erase_grp_size=%d erase_grp_mult=%d", 		      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);	MMC_DEBUG(2,"cmd=%d status=%08x", r1->cmd, r1->status);	/* SD card return in upper status the cardid */	if (R1_STATUS(r1->status) && request->cmd!=MMC_SET_RELATIVE_ADDR) {		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_cid_mmc( 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];		MMC_DEBUG(2,"mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d",	      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_cid_sd( struct mmc_request *request, struct mmc_cid *cid ){	u8 *buf = request->response;	int i;	if ( request->result ) return request->result;	/*	 * Packed CID Format	 *	 * Field|size|   slice   | byte  | Description	 *	 *  MID |  8 | [127:120] | [ 0: 0] | Manufacture ID [$02 = Toshiba ]	 *  OID | 16 | [119:104] | [ 1: 2] | Manufacture ID [$544D "TM" = Toshiba ]	 *  PNM | 40 | [103: 64] | [ 3: 7] | Product Name Manufacture [SD044 | SD128 | SD256 for toshiba sdcard ]	 *  PRV |  8 | [ 63: 56] | [ 8: 8] | Product Revision	 *  PSN | 32 | [ 55: 24] | [ 9:12] | Product Serial Number	 *   -  |  4 | [ 23: 20] | [13:13] | All zeros	 *  MDT | 12 | [ 19:  8] | [13:14] | Manufacture Date [11:8] Month / [19:12] Year + 2000	 *  CRC |  7 | [  7:  1] | [15:15] | CRC	 *   -  |  1 | [  0:  0] | [15:15] | 1	 */	cid->mid = buf[1];	cid->oid = PARSE_U16(buf,2);	for ( i = 0 ; i < 5 ; i++ )		cid->pnm[i] = buf[4+i];	cid->pnm[5] = 0;	cid->prv = buf[9];	cid->psn = PARSE_U32(buf,10);	cid->mdt = (buf[14]<<4)|buf[15];		MMC_DEBUG(2,"mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d",	      cid->mid, cid->oid, cid->pnm, 	      (cid->prv>>4), (cid->prv&0xf), 	      cid->psn, (cid->mdt>>4), (cid->mdt&0xf)+2000);	if ( buf[0]  != 0x3f )  return MMC_ERROR_HEADER_MISMATCH;	if ( !(buf[16]&1)    )  return MMC_ERROR_CARD_ECC_FAILED;      	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);	MMC_DEBUG(2,"ocr=%08x", 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 ) {		MMC_DEBUG(0, ": error - unrecognized speed 0x%02x", 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;	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)	if ( slot->media_driver )		slot->media_driver->io_request_done( t, result );}/* 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;	MMC_DEBUG(2,"dev state=%x", 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;			}			/* Clear eject & SD card here in case the next			 * card is an MMC. Cannot clear all as suspend			 * resume will queue eject & insert together. */			slot->flags &=				~(MMC_SLOT_FLAG_EJECT | MMC_SLOT_FLAG_SDCARD);			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;	MMC_DEBUG(2,"dev state=%x", dev->state);	local_irq_save(flags);	state = dev->state;	dev->state = state & ~STATE_INSERT;	local_irq_restore(flags);	if ( !(state & STATE_INSERT) ) 		return 0;	for ( i = 0 ; i < dev->num_slots ; i++ ) {		struct mmc_slot *slot = dev->slot + i;		if ( slot->flags & MMC_SLOT_FLAG_INSERT ) {			if  (!dev->sdrive->is_empty(i)) {				slot->state = CARD_STATE_IDLE;				card_count++;			}			slot->flags &= ~MMC_SLOT_FLAG_INSERT;		}	}	return card_count;}/****************************************************************** * * Hotplug callback card insertion/removal * ******************************************************************/

⌨️ 快捷键说明

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