📄 mmc_protocol.c
字号:
/* Core MMC driver functions * * Copyright (c) 2002 Hewlett-Packard Company * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Many thanks to Alessandro Rubini and Jonathan Corbet! * * Author: Andrew Christian * 6 May 2002 *(C) Copyright 2006 Marvell International Ltd. * All Rights Reserved *//* * mmc_protocol.c - MMC protocol driver * * Copyright (C) 2006 Intel Corporation * * 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 program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/list.h>#include <linux/sysctl.h>#include <linux/mm.h>#include <asm/scatterlist.h>#include <linux/mmc/mss_core.h>#include <linux/mmc/mmc_protocol.h>/* internal functions */#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 };static u32 mmc_tran_speed(u8 ts){ u32 clock = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3]; dbg("MMC clock is %d\n", clock); return clock;}static int mmc_unpack_r1(struct mss_cmd *cmd, struct mmc_response_r1 *r1, struct mmc_card *mmc_card){ u8 *buf = cmd->response; mmc_card->errno = MMC_ERROR_NONE; r1->cmd = unstuff_bits(buf, 40, 8, 6); r1->status = unstuff_bits(buf, 8, 32, 6); if (R1_STATUS(r1->status)) { if (r1->status & R1_OUT_OF_RANGE) mmc_card->errno = MMC_ERROR_OUT_OF_RANGE; if (r1->status & R1_ADDRESS_ERROR) mmc_card->errno = MMC_ERROR_ADDRESS; if (r1->status & R1_BLOCK_LEN_ERROR) mmc_card->errno = MMC_ERROR_BLOCK_LEN; if (r1->status & R1_ERASE_SEQ_ERROR) mmc_card->errno = MMC_ERROR_ERASE_SEQ; if (r1->status & R1_ERASE_PARAM) mmc_card->errno = MMC_ERROR_ERASE_PARAM; if (r1->status & R1_WP_VIOLATION) mmc_card->errno = MMC_ERROR_WP_VIOLATION; if (r1->status & R1_LOCK_UNLOCK_FAILED) mmc_card->errno = MMC_ERROR_LOCK_UNLOCK_FAILED; if (r1->status & R1_COM_CRC_ERROR) mmc_card->errno = MMC_ERROR_COM_CRC; if (r1->status & R1_ILLEGAL_COMMAND) mmc_card->errno = MMC_ERROR_ILLEGAL_COMMAND; if (r1->status & R1_CARD_ECC_FAILED) mmc_card->errno = MMC_ERROR_CARD_ECC_FAILED; if (r1->status & R1_CC_ERROR) mmc_card->errno = MMC_ERROR_CC; if (r1->status & R1_ERROR) mmc_card->errno = MMC_ERROR_GENERAL; if (r1->status & R1_UNDERRUN) mmc_card->errno = MMC_ERROR_UNDERRUN; if (r1->status & R1_OVERRUN) mmc_card->errno = MMC_ERROR_OVERRUN; if (r1->status & R1_CID_CSD_OVERWRITE) mmc_card->errno = MMC_ERROR_CID_CSD_OVERWRITE; } if (buf[0] != cmd->opcode) mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; /* This should be last - it's the least dangerous error */ if (R1_CURRENT_STATE(r1->status) != mmc_card->state ) { dbg("state dismatch:r1->status:%x,state:%x\n", R1_CURRENT_STATE(r1->status),mmc_card->state); mmc_card->errno = MMC_ERROR_STATE_MISMATCH; } dbg("mmc card error %d", mmc_card->errno); if (mmc_card->errno) return MSS_ERROR_RESP_UNPACK; return 0;}static int mmc_unpack_r3(struct mss_cmd *cmd, struct mmc_response_r3 *r3, struct mmc_card *mmc_card){ u8 *buf = cmd->response; mmc_card->errno = MMC_ERROR_NONE; r3->cmd = unstuff_bits(buf, 40, 8, 6); r3->ocr = unstuff_bits(buf, 8, 32, 6); if (r3->cmd != 0x3f) { mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } return 0;}/** * Fast I/O, support for CEATA devices. */static int mmc_unpack_r4( struct mss_cmd *cmd, struct mmc_response_r4 *r4, struct mmc_card *mmc_card){ u8 *buf = cmd->response; mmc_card->errno = MMC_ERROR_NONE; r4->cmd = unstuff_bits(buf, 40, 8, 6); r4->rca = unstuff_bits(buf, 24, 16, 6); r4->status = unstuff_bits(buf, 23, 1, 6); r4->reg_addr = unstuff_bits(buf, 16, 7, 6); r4->read_reg_contents = unstuff_bits(buf, 8, 8, 6); if (r4->cmd != 0x27) { mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } return 0 ;}/** * Interrupt request. not supported temporarily. */static int mmc_unpack_r5(struct mss_cmd *cmd, struct mmc_response_r5 *r5, struct mmc_card *mmc_card){ u8 *buf = cmd->response; mmc_card->errno = MMC_ERROR_NONE; r5->cmd = unstuff_bits(buf, 40, 8, 6); r5->rca = unstuff_bits(buf, 24, 16, 6); r5->irq_data = unstuff_bits(buf, 8, 16, 6); if (r5->cmd != 0x28) { mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } return 0 ;}static int mmc_unpack_cid(struct mss_cmd *cmd, struct mmc_cid *cid, struct mmc_card *mmc_card){ u8 *buf = cmd->response; mmc_card->errno = MMC_ERROR_NONE; if (buf[0] != 0x3f) { mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } buf = buf + 1; cid->mid = unstuff_bits(buf, 120, 8, 16); cid->oid = unstuff_bits(buf, 104, 16, 16); cid->pnm[0] = unstuff_bits(buf, 96, 8, 16); cid->pnm[1] = unstuff_bits(buf, 88, 8, 16); cid->pnm[2] = unstuff_bits(buf, 80, 8, 16); cid->pnm[3] = unstuff_bits(buf, 72, 8, 16); cid->pnm[4] = unstuff_bits(buf, 64, 8, 16); cid->pnm[5] = unstuff_bits(buf, 56, 8, 16); cid->pnm[6] = 0; cid->prv = unstuff_bits(buf, 48, 8, 16); cid->psn = unstuff_bits(buf, 16, 32, 16); cid->mdt = unstuff_bits(buf, 8, 8, 16); #if 0 DEBUG(" 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&&0xf, ((cid->mdt>>4)&0xff)+2000);#endif return 0;}static int mmc_unpack_csd(struct mss_cmd *cmd, struct mmc_csd *csd, struct mmc_card *mmc_card){ u8 *buf = cmd->response; mmc_card->errno = MMC_ERROR_NONE; if (buf[0] != 0x3f) { mmc_card->errno = MMC_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } buf = buf + 1; csd->csd_structure = unstuff_bits(buf, 126, 2, 16); csd->spec_vers = unstuff_bits(buf, 122, 4, 16); csd->taac = unstuff_bits(buf, 112, 8, 16); csd->nsac = unstuff_bits(buf, 104, 8, 16); csd->tran_speed = unstuff_bits(buf, 96, 8, 16); csd->ccc = unstuff_bits(buf, 84, 12, 16);; csd->read_bl_len = unstuff_bits(buf, 80, 4, 16); csd->read_bl_partial = unstuff_bits(buf, 79, 1, 16); csd->write_blk_misalign = unstuff_bits(buf, 78, 1, 16); csd->read_blk_misalign = unstuff_bits(buf, 77, 1, 16); csd->dsr_imp = unstuff_bits(buf, 76, 1, 16); csd->c_size = unstuff_bits(buf, 62, 12, 16); csd->vdd_r_curr_min = unstuff_bits(buf, 59, 3, 16); csd->vdd_r_curr_max = unstuff_bits(buf, 56, 3, 16); csd->vdd_w_curr_min = unstuff_bits(buf, 53, 3, 16); csd->vdd_w_curr_max = unstuff_bits(buf, 50, 3, 16); csd->c_size_mult = unstuff_bits(buf, 47, 3, 16); switch (csd->csd_structure ) { case CSD_STRUCT_1_0: case CSD_STRUCT_1_1: csd->erase.v22.sector_size = unstuff_bits(buf, 42, 5, 16); csd->erase.v22.erase_grp_size = unstuff_bits(buf, 37, 5, 6); break; case CSD_STRUCT_1_2: default: csd->erase.v31.erase_grp_size = unstuff_bits(buf, 42, 5, 16); csd->erase.v31.erase_grp_mult = unstuff_bits(buf, 37, 5, 16);; break; } csd->wp_grp_size = unstuff_bits(buf, 32, 5, 16); csd->wp_grp_enable = unstuff_bits(buf, 31, 1, 16); csd->default_ecc = unstuff_bits(buf, 29, 2, 16); csd->r2w_factor = unstuff_bits(buf, 26, 3, 16); csd->write_bl_len = unstuff_bits(buf, 22, 4, 16); csd->write_bl_partial = unstuff_bits(buf, 21, 1, 16); csd->file_format_grp = unstuff_bits(buf, 16, 1, 16); csd->copy = unstuff_bits(buf, 14, 1, 16); csd->perm_write_protect = unstuff_bits(buf, 13, 1, 16); csd->tmp_write_protect = unstuff_bits(buf, 12, 1, 16); csd->file_format = unstuff_bits(buf, 10, 2, 16); csd->ecc = unstuff_bits(buf, 8, 2, 16);#if 0 printk("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_1_0: case CSD_STRUCT_1_1: printk(" V22 sector_size=%d erase_grp_size=%d\n", csd->erase.v22.sector_size, csd->erase.v22.erase_grp_size); break; case CSD_STRUCT_1_2: default: printk(" V31 erase_grp_size=%d erase_grp_mult=%d\n", csd->erase.v31.erase_grp_size, csd->erase.v31.erase_grp_mult); break; }#endif return MSS_ERROR_NONE;}static int mmc_unpack_ext_csd(u8 *buf, struct mmc_ext_csd *ext_csd){ ext_csd->s_cmd_set = buf[504]; ext_csd->sec_count = ((u32)buf[212]) << 24 | ((u32)buf[213]) << 16 | ((u32)buf[214]) << 8 | ((u32)buf[215]) ; ext_csd->min_perf_w_8_52 = buf[210]; ext_csd->min_perf_r_8_52 = buf[209]; ext_csd->min_perf_w_26_4_52 = buf[208]; ext_csd->min_perf_r_26_4_52 = buf[207]; ext_csd->min_perf_w_4_26 = buf[206]; ext_csd->min_perf_r_4_26 = buf[205]; ext_csd->pwr_cl_26_360 = buf[203]; ext_csd->pwr_cl_52_360 = buf[202]; ext_csd->pwr_cl_26_195 = buf[201]; ext_csd->pwr_cl_52_195 = buf[200]; ext_csd->card_type = buf[196]; ext_csd->csd_structure = buf[194]; ext_csd->ext_csd_rev = buf[192]; ext_csd->cmd_set = buf[191]; ext_csd->cmd_set_rev = buf[189]; ext_csd->power_class = buf[187]; ext_csd->hs_timing = buf[185]; ext_csd->erased_mem_cont = buf[183];#if 0 DEBUG("s_cmd_set:%d, sec_count:%d, min_perf_w_8_52:%d,\n" "min_perf_r_8_52:%d, min_perf_w_26_4_52:%d, min_perf_r_26_4_52:%d\n" "min_perf_w_4_26:%d, min_perf_r_4_26:%d, pwr_cl_26_360:%d, " "pwr_cl_52_360:%d, pwr_cl_26_195:%d, pwr_cl_52_195:%d, card_type:%d\n" "csd_structure:%d, ext_csd_rev:%d, cmd_set:%d, cmd_set_rev:%d\n" "power_class:%d, hs_timing:%d, erased_mem_cont:%d\n", ext_csd->s_cmd_set,ext_csd->sec_count,ext_csd->min_perf_w_8_52, ext_csd->min_perf_r_8_52,ext_csd->min_perf_w_26_4_52,ext_csd->min_perf_r_26_4_52, ext_csd->min_perf_w_4_26, ext_csd->min_perf_r_4_26, ext_csd->pwr_cl_26_360, ext_csd->pwr_cl_52_360, ext_csd->pwr_cl_26_195, ext_csd->pwr_cl_52_195, ext_csd->card_type, ext_csd->csd_structure, ext_csd->ext_csd_rev, ext_csd->cmd_set, ext_csd->cmd_set_rev, ext_csd->power_class, ext_csd->hs_timing, ext_csd->erased_mem_cont); #endif return 0;}#ifdef CONFIG_MMC_CEATAstatic int mmc_unpack_ceata(u8 *buf, struct mmc_ceata *ceata){/* memcpy(ceata->sn, buf + 20, 20); memcpy(ceata->fw_ver, buf + 46, 8); memcpy(ceata->model_number, buf + 54, 40); ceata->major_ver = buf[160] << 8 | buf[161]; ceata->max_lba = ((u64)buf[200] << 56) | ((u64)buf[201] << 48) | ((u64)buf[202] << 40) | ((u64)buf[203] << 32) | ((u64)buf[204] << 24) | ((u64)buf[205] << 16) | ((u64)buf[206] << 8) | (u64)(buf[207]); ceata->feature = buf[512] << 8 | buf[513]; dbg("max_lbr : 0x%llx", ceata->max_lba);*/ return 0;}#endif/** * The blocks requested by the kernel may or may not match what we can do. * Unfortunately, filesystems play fast and loose with block sizes, so we're * stuck with this . */static void mmc_fix_request_block_len(struct mss_card *card, int action, struct mss_rw_arg *arg){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -