📄 sd_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 *//* * sd_protocol.c - SD 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 * * Author: Bridge Wu <bridge.wu@intel.com> * *(C) Copyright 2006 Marvell International Ltd. * All Rights Reserved * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.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/mm.h>#include <asm/scatterlist.h>#include <linux/mmc/mss_core.h>#include <linux/mmc/sd_protocol.h>#if 0static char * sd_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", "ERROR_FLASH",};static char * sd_state_strings[] = { "empty", "idle", "ready", "ident", "stby", "tran", "data", "rcv", "prg", "dis",};/***************************************************************************** * * internal functions * ****************************************************************************/static inline char * sd_result_to_string( int i ){ return sd_result_strings[i+1];}static inline char * sd_state_to_string( int i ){ return sd_state_strings[i+1];}#endif#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 sd_tran_speed(u8 ts){ u32 clock = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3]; return clock;}static int sd_unpack_r1(struct mss_cmd *cmd, struct sd_response_r1 *r1, struct sd_card *sd_card){ u8 *buf = cmd->response; sd_card->errno = SD_ERROR_NONE; r1->cmd = unstuff_bits(buf, 40, 8, 6); r1->status = unstuff_bits(buf, 8, 32, 6); /* dbg("status 0x%x", r1->status);*/ if (R1_STATUS(r1->status)) { if (r1->status & R1_OUT_OF_RANGE) sd_card->errno = SD_ERROR_OUT_OF_RANGE; if (r1->status & R1_ADDRESS_ERROR) sd_card->errno = SD_ERROR_ADDRESS; if (r1->status & R1_BLOCK_LEN_ERROR) sd_card->errno = SD_ERROR_BLOCK_LEN; if (r1->status & R1_ERASE_SEQ_ERROR) sd_card->errno = SD_ERROR_ERASE_SEQ; if (r1->status & R1_ERASE_PARAM) sd_card->errno = SD_ERROR_ERASE_PARAM; if (r1->status & R1_WP_VIOLATION) sd_card->errno = SD_ERROR_WP_VIOLATION; if (r1->status & R1_LOCK_UNLOCK_FAILED) sd_card->errno = SD_ERROR_LOCK_UNLOCK_FAILED; if (r1->status & R1_COM_CRC_ERROR) sd_card->errno = SD_ERROR_COM_CRC; if (r1->status & R1_ILLEGAL_COMMAND) sd_card->errno = SD_ERROR_ILLEGAL_COMMAND; if (r1->status & R1_CARD_ECC_FAILED) sd_card->errno = SD_ERROR_CARD_ECC_FAILED; if (r1->status & R1_CC_ERROR) sd_card->errno = SD_ERROR_CC; if (r1->status & R1_ERROR) sd_card->errno = SD_ERROR_GENERAL; if (r1->status & R1_CID_CSD_OVERWRITE) sd_card->errno = SD_ERROR_CID_CSD_OVERWRITE; } if (r1->status & R1_AKE_SEQ_ERROR) sd_card->errno = SD_ERROR_CID_CSD_OVERWRITE; if (r1->cmd != cmd->opcode) sd_card->errno = SD_ERROR_HEADER_MISMATCH; /* This should be last - it's the least dangerous error */ if (R1_CURRENT_STATE(r1->status) != sd_card->state ) { dbg("state dismatch:r1->status:%x,state:%x\n",R1_CURRENT_STATE(r1->status),sd_card->state); sd_card->errno = SD_ERROR_STATE_MISMATCH; } dbg("sd card error %d", sd_card->errno); if (sd_card->errno) return MSS_ERROR_RESP_UNPACK; return 0;}static int sd_unpack_r3(struct mss_cmd *cmd, struct sd_response_r3 *r3, struct sd_card *sd_card){ u8 *buf = cmd->response; sd_card->errno = SD_ERROR_NONE; r3->cmd = unstuff_bits(buf, 40, 8, 6); r3->ocr = unstuff_bits(buf, 8, 32, 6); dbg("ocr=0x%x", r3->ocr); if (r3->cmd != 0x3f) { sd_card->errno = SD_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } return 0;} static int sd_unpack_r6(struct mss_cmd *cmd, struct sd_response_r6 *r6, struct sd_card *sd_card){ u8 *buf = cmd->response; int errno = SD_ERROR_NONE; r6->cmd = unstuff_bits(buf, 40, 8, 6); r6->rca = unstuff_bits(buf, 24, 16, 6); r6->status = unstuff_bits(buf, 8, 16, 6); if (R6_STATUS(r6->status)) { if (r6->status & R6_COM_CRC_ERROR) errno = SD_ERROR_COM_CRC; if (r6->status & R6_ILLEGAL_COMMAND) errno = SD_ERROR_ILLEGAL_COMMAND; if (r6->status & R6_ERROR) errno = SD_ERROR_CC; } if (r6->cmd != cmd->opcode) errno = SD_ERROR_HEADER_MISMATCH; /* This should be last - it's the least dangerous error */ if (R1_CURRENT_STATE(r6->status) != sd_card->state) errno = SD_ERROR_STATE_MISMATCH; sd_card->errno = errno; if (errno) return MSS_ERROR_RESP_UNPACK; return 0 ;}static int sd_unpack_cid(struct mss_cmd *cmd, struct sd_cid *cid, struct sd_card *sd_card){ u8 *buf = cmd->response; sd_card->errno = SD_ERROR_NONE; if (buf[0] != 0x3f) { sd_card->errno = SD_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] = 0; cid->prv = unstuff_bits(buf, 56, 8, 16); cid->psn = unstuff_bits(buf, 24, 32, 16); cid->mdt = unstuff_bits(buf, 8, 12, 16);/* 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);*/ return 0;}static int sd_unpack_csd(struct mss_cmd *cmd, struct sd_csd *csd, struct sd_card *sd_card){ u8 *buf = cmd->response; sd_card->errno = SD_ERROR_NONE; if (buf[0] != 0x3f) { sd_card->errno = SD_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } buf = buf + 1; csd->csd_structure = unstuff_bits(buf, 126, 2, 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); if (csd->csd_structure == 0) { csd->csd.csd1.c_size = unstuff_bits(buf, 62, 12, 16); csd->csd.csd1.vdd_r_curr_min = unstuff_bits(buf, 59, 3, 16); csd->csd.csd1.vdd_r_curr_max = unstuff_bits(buf, 56, 3, 16); csd->csd.csd1.vdd_w_curr_min = unstuff_bits(buf, 53, 3, 16); csd->csd.csd1.vdd_w_curr_max = unstuff_bits(buf, 50, 3, 16); csd->csd.csd1.c_size_mult = unstuff_bits(buf, 47, 3, 16); } else if (csd->csd_structure == 1) { csd->csd.csd2.c_size = unstuff_bits(buf, 48, 22, 16); } csd->erase_blk_en = unstuff_bits(buf, 46, 1, 16); csd->sector_size = unstuff_bits(buf, 39, 7, 16); csd->wp_grp_size = unstuff_bits(buf, 32, 7, 16); csd->wp_grp_enable = unstuff_bits(buf, 31, 1, 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, 15, 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);#if 0 if (csd->csd_structure == 0) { dbg5(" csd_structure=%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_en=%d 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->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->csd.csd1.c_size, csd->csd.csd1.vdd_r_curr_min, csd->csd.csd1.vdd_r_curr_max, csd->csd.csd1.vdd_w_curr_min, csd->csd.csd1.vdd_w_curr_max, csd->csd.csd1.c_size_mult, csd->erase_blk_en,csd->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); } else if (csd->csd_structure == 1) { dbg5(" csd_structure=%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\n" " erase_blk_en=%d 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->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->csd.csd2.c_size, csd->erase_blk_en,csd->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); }#endif return 0;}static int sd_unpack_swfuncstatus(char *buf, struct sw_func_status *status){ int i; buf += 34; for (i = 0; i < 5; i++) { status->func_busy[i] = buf[0] << 8 | buf[1]; buf += 2; } buf += 1; for (i = 0; i <= 5; i = i + 2) { status->group_status[i] = buf[0] & 0xFF; status->group_status[(i + 1)] = (buf[0] >> 4) & 0xFF; buf += 1; } for (i = 0; i <= 5; i++) { status->func_support[i] = buf[0] << 8 | buf[1]; buf += 2; } status->current_consumption = buf[0] << 8 | buf[1]; return 0;}static int sd_unpack_r7(struct mss_cmd *cmd, struct sd_response_r7 *r7, u16 arg, struct sd_card *sd_card){ u8 *buf = cmd->response; r7->cmd = unstuff_bits(buf, 40, 8, 6); r7->ver = unstuff_bits(buf, 20, 20, 6); r7->vca = unstuff_bits(buf, 16, 4, 6); r7->pattern = unstuff_bits(buf, 8, 8, 6); if (r7->cmd != SD_SEND_IF_COND || r7->ver != 0 || (r7->vca << 8 | r7->pattern) != arg) { sd_card->errno = SD_ERROR_HEADER_MISMATCH; return MSS_ERROR_RESP_UNPACK; } return 0;}static int sd_unpack_scr(u8 *buf, struct sd_scr *scr){ scr->scr_structure = unstuff_bits(buf, 60, 4, 8); scr->sd_spec = unstuff_bits(buf, 56, 4, 8); scr->data_stat_after_erase = unstuff_bits(buf, 55, 1, 8); scr->sd_security = unstuff_bits(buf, 52, 3, 8); scr->sd_bus_width = unstuff_bits(buf, 48, 4, 8); scr->init = 1; dbg("scr_stru:%d, spec:%d, sata:%d, security:%d, bus:%d", scr->scr_structure, scr->sd_spec,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -