📄 mmc_core.c
字号:
/* * 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 */#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>#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;#elseint g_mmc_debug = 0;#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; 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; 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;}/* Wangzheng */int sd_unpack_csd( struct mmc_request *request, struct sd_csd *csd ){ u8 *buf = request->response; if ( request->result ) return request->result; csd->csd_structure = (buf[1] & 0xc0) >> 6; 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); csd->erase_blk_enable = (buf[11]&0x40)>>6; csd->erase_sector_size = ((buf[11]&0x3f)<<1) | ((buf[12]&0x80)>>7); csd->wp_grp_size = buf[12]&0x7f; csd->wp_grp_enable = (buf[13]&0x80)>>7; 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; 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" " erase_blk_enable=%d erase_sector_size=%d wp_grp_size=%d wp_grp_enable=%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\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->erase_blk_enable, csd->erase_sector_size, csd->wp_grp_size, csd->wp_grp_enable, 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); 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;}/* Wangzheng */int sd_unpack_r6( struct mmc_request *request, struct sd_response_r6 *r6, enum card_state state ){ u8 *buf = request->response; if ( request->result ) return request->result; r6->cmd = buf[0]; r6->rca = PARSE_U16(buf,1); r6->status = PARSE_U16(buf,3); DEBUG(2," cmd=%d rca = %08x status=%08x\n", r6->cmd, r6->rca, r6->status); 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( 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;}/* Wangzheng */int sd_unpack_cid( struct mmc_request *request, struct sd_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 < 5 ; i++ ) cid->pnm[i] = buf[4+i]; cid->pnm[5] = 0; cid->prv = buf[10]; cid->psn = PARSE_U32(buf,10); cid->mdt = (u16)((buf[14]&0xf)<<8) + buf[15] ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -