📄 sdio_protocol.c
字号:
* * protocol entry functions * ****************************************************************************/static int sdio_recognize_card(struct mss_card *card){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r4 r4; struct mss_ios ios; int ret; card->card_type = MSS_UNKNOWN_CARD; sdio_card->state = CARD_STATE_INIT; card->bus_width = MSS_BUSWIDTH_1BIT; memcpy(&ios, &host->ios, sizeof(struct mss_ios)); ios.clock = host->f_min; ios.bus_width = MSS_BUSWIDTH_1BIT; host->ops->set_ios(host, &ios); /* check if a sdio card, need not send CMD0 to reset for SDIO card */ ret = mss_send_simple_ll_req(host, llreq, cmd, IO_SEND_OP_COND, 0, MSS_RESPONSE_R4, 0); if (ret) return ret; ret = sdio_unpack_r4(cmd, &r4, sdio_card); if (ret) return ret; sdio_card->func_num = r4.func_num; sdio_card->mem_present = r4.mem_present; if (!r4.func_num) return MSS_ERROR_NONE; /* maybe COMBO_CARD. but we can return SDIO_CARD first, * in sdio_card_init, we will judge further. */ if(r4.ocr & host->vdd) { card->card_type = MSS_SDIO_CARD; } else { printk(KERN_WARNING "uncompatible card\n"); card->card_type = MSS_UNCOMPATIBLE_CARD; } return MSS_ERROR_NONE;}static int sdio_card_init(struct mss_card *card){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r1 r1; struct sdio_response_r4 r4; struct sdio_response_r6 r6; struct mss_ios ios; int ret, tmp, i; u8 funcs; /* It is better for sdio reset here to re-init */ if (card->state & MSS_CARD_REGISTERED) { sdio_reset(card); card->state &= ~MSS_CARD_INITED; } sdio_card->state = CARD_STATE_INIT; card->bus_width = MSS_BUSWIDTH_1BIT; memcpy(&ios, &host->ios, sizeof(struct mss_ios)); ios.clock = host->f_min; ios.bus_width = MSS_BUSWIDTH_1BIT; host->ops->set_ios(host, &ios); ret = mss_send_simple_ll_req(host, llreq, cmd, IO_SEND_OP_COND, host->vdd, MSS_RESPONSE_R4, 0); if (ret) return ret; ret = sdio_unpack_r4(cmd, &r4, sdio_card); if (ret) return ret; while (!r4.ready) { mdelay(20); ret = mss_send_simple_ll_req(host, llreq, cmd, IO_SEND_OP_COND, host->vdd, MSS_RESPONSE_R4, 0); if (ret) return ret; ret = sdio_unpack_r4(cmd, &r4, sdio_card); if (ret) return ret; } ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SET_RELATIVE_ADDR, 0, MSS_RESPONSE_R6, 0); if (ret) return ret; ret = sdio_unpack_r6(cmd, &r6, sdio_card); if (ret) return ret; sdio_card->state = CARD_STATE_STBY; sdio_card->rca = r6.rca; ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SELECT_CARD, (sdio_card->rca) << 16, MSS_RESPONSE_R1B, 0); if (ret) return ret; ret = sdio_unpack_r1(cmd, &r1, sdio_card); if (ret) return ret; /** CARD_STATE_CMD */ //slot->state = CARD_STATE_CMD; //send CMD53 to let DATA BUS FREE, since bus_suspend not supported, need not to do this //arg = sdio_make_cmd53_arg(SDIO_READ, 0, 0, 0, 0, 1); //mss_simple_cmd( dev, IO_RW_EXTENDED, arg, RESPONSE_R5); /** CARD_STATE_TRAN */ sdio_card->state = CARD_STATE_CMD; ret = get_sdio_cccr_info(card); if (ret) return ret; dbg("bus_width is %d\n", host->bus_width); if(host->bus_width == MSS_BUSWIDTH_4BIT && (!sdio_card->cccr.lsc || sdio_card->cccr.ls4b)) { sdio_set_bus_width(card, 2); } funcs = sdio_card->func_num; /* enable function */ tmp = 0; for(i = 1; i <= funcs; i++) { tmp |= (1 << i); } ret = sdio_io_enable(card, tmp); if (ret) return ret; for(i = 1; i <= funcs; i++) { ret = get_sdio_fbr_info(card, i); if (ret) return ret; } ret = get_sdio_ccis_info(card); if (ret) return ret; for(i = 1; i <= funcs; i++) { ret = get_sdio_fcis_info(card, i); if (ret) return ret; } /* enable interrupt */ tmp = 1; for(i = 1; i <= funcs; i++) { tmp |= (1 << i); } ret = sdio_interrupt_enable(card, tmp); if (ret) return ret; /* enable card capabilites */ for (i=1; i <= funcs; i++) { sdio_csa_enable(card, i); } mss_set_sdio_int(card->slot->host, 1); sdio_card->state = CARD_STATE_TRAN; return MSS_ERROR_NONE;}static int sdio_read_write_entry(struct mss_card *card, int action, struct mss_rw_arg *arg, struct mss_rw_result *result){ struct mss_host *host = card->slot->host; struct sdio_card *sdio_card = card->prot_card; struct mss_cmd *cmd = &sdio_card->cmd; struct mss_data *data = &sdio_card->data; struct mss_ll_request *llreq = &sdio_card->llreq; struct sdio_response_r5 r5; struct sdio_response_r1 r1; int ret; u32 addr, blkmode, func, rw, rw_count, opcode, clock, cmdarg; int retries = 4; if (sdio_card->state == CARD_STATE_STBY) { ret = mss_send_simple_ll_req(host, llreq, cmd, SD_SELECT_CARD, sdio_card->rca << 16, MSS_RESPONSE_R1B, 0); if (ret) return ret; ret = sdio_unpack_r1(cmd, &r1, sdio_card); if (ret) return ret; } mss_set_clock(host, sdio_tran_speed(sdio_card->ccis.max_tran_speed)); func = arg->func; if (func > sdio_card->func_num) return MSS_ERROR_WRONG_ARG; if (arg->block_len == 0 || arg->block_len == 1) { blkmode = 0; } else { if (!sdio_card->cccr.smb) return MSS_ERROR_WRONG_ARG; dbg("blkzs:%d, %d\n", arg->block_len, sdio_card->fbr[func].fn_blksz); if (arg->block_len != sdio_card->fbr[func].fn_blksz) { ret = sdio_set_block_size(card, arg->block_len, func); if (ret) return ret; } blkmode = 1; } rw = (action == MSS_READ_MEM) ? 0 : 1; addr = arg->block; opcode = (arg->opcode) ? 1 : 0; rw_count = arg->nob; read_write_entry: memset(llreq, 0x0, sizeof(struct mss_ll_request)); memset(cmd, 0x0, sizeof(struct mss_cmd)); memset(data, 0x0, sizeof(struct mss_data)); /* deal with request */ /* if only one byte, then use CMD52 to read*/ if (!blkmode && rw_count == 1) { u8 val = (rw) ? arg->val : 0; dbg("use CMD52 to transfer data. rw direction: %d", rw); cmdarg = sdio_make_cmd52_arg(rw, func, opcode, addr, val); ret = mss_send_simple_ll_req(host, llreq, cmd, IO_RW_DIRECT, cmdarg, MSS_RESPONSE_R5, MSS_CMD_SDIO_EN); if (!ret) ret = sdio_unpack_r5(cmd, &r5, sdio_card); if (!ret) result->bytes_xfered = r5.data; else if (ret && --retries) { clock = host->ios.clock; clock = clock >> 1; if (clock < SDIO_CARD_CLOCK_SLOW && retries == 1) { clock = SDIO_CARD_CLOCK_SLOW; mss_set_clock(host, clock); goto read_write_entry; } return ret; } dbg("r5.data:0x%x\n",r5.data); } else { cmdarg= sdio_make_cmd53_arg(rw, func, blkmode, opcode, addr, rw_count); MSS_INIT_CMD(cmd, IO_RW_EXTENDED, cmdarg, MSS_CMD_SDIO_EN, MSS_RESPONSE_R5); MSS_INIT_DATA(data, rw_count, arg->block_len, ((rw) ? MSS_DATA_WRITE : MSS_DATA_READ), arg->sg_len, arg->sg, 0); llreq->cmd = cmd; llreq->data = data; ret = mss_send_ll_req(host, llreq); if (!ret) ret = sdio_unpack_r5(cmd, &r5, sdio_card); if (ret) { if (--retries) { clock = host->ios.clock; clock = clock >> 1; if (clock < SDIO_CARD_CLOCK_SLOW && retries == 1) clock = SDIO_CARD_CLOCK_SLOW; mss_set_clock(host, clock); goto read_write_entry; } return ret; } } return MSS_ERROR_NONE;}/***************************************************************************** * * protocol driver interface functions * ****************************************************************************/static int sdio_prot_entry(struct mss_card *card, unsigned int action, void *arg, void *result){ int ret; dbg("sdio_prot_entry\n"); if (action != MSS_RECOGNIZE_CARD && card->card_type != MSS_SDIO_CARD) return MSS_ERROR_WRONG_CARD_TYPE; switch (action) { case MSS_RECOGNIZE_CARD: ret = sdio_recognize_card(card); break; case MSS_INIT_CARD: ret = sdio_card_init(card); break; case MSS_READ_MEM: case MSS_WRITE_MEM: if (!arg || !result) return -EINVAL; ret = sdio_read_write_entry(card, action, arg, result); break; case MSS_QUERY_CARD: ret = MSS_ERROR_NONE; break; default: ret = MSS_ERROR_ACTION_UNSUPPORTED; break; } return ret;}static int sdio_prot_attach_card(struct mss_card *card){ struct sdio_card *sdio_card; dbg("sdio_prot_attach_card\n");#define ALIGN32(x) (((x) + 31) & (~31)) sdio_card = kzalloc(ALIGN32(sizeof(struct sdio_card)), GFP_KERNEL); card->prot_card = sdio_card; if (sdio_card) { return 0; } return -ENOMEM;}static void sdio_prot_detach_card(struct mss_card *card){ kfree(card->prot_card);}static int sdio_prot_get_errno(struct mss_card *card){ struct sdio_card *sdio_card = card->prot_card; return sdio_card->errno;}static struct mss_prot_driver sdio_protocol = { .name = SDIO_PROTOCOL, .prot_entry = sdio_prot_entry, .attach_card = sdio_prot_attach_card, .detach_card = sdio_prot_detach_card, .get_errno = sdio_prot_get_errno,};/***************************************************************************** * * module init and exit functions * ****************************************************************************/static int sdio_protocol_init(void){ register_mss_prot_driver(&sdio_protocol); return 0;}static void sdio_protocol_exit(void){ unregister_mss_prot_driver(&sdio_protocol);}module_init(sdio_protocol_init);module_exit(sdio_protocol_exit);MODULE_AUTHOR("Bridge Wu");MODULE_LICENSE("Intel Private");MODULE_DESCRIPTION("SDIO protocol driver");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -