?? 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 *//* * 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 + -