📄 mmc.c
字号:
} memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_DIS_PULL_UP; cmd.arg = 0; cmd.flags = MMCSD_RSP1; err = mmc_wait_for_cmd(host, &cmd, 0); if ((err != MMC_ERR_NONE) || !(cmd.resp[6] & R1_APP_CMD)) { mmc_card_set_dead(card); continue; } } mmc_deselect_cards(host);}static void mmc_read_scrs(struct mmc_host *host){ int err; struct mmc_card *card; struct mmc_request mrq; struct mmc_command cmd; char scr_reg[8]; list_for_each_entry(card, &host->cards, node) { if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) continue; if (!mmc_card_sd(card)) continue; err = mmc_select_card(host, card); if (err != MMC_ERR_NONE) { mmc_card_set_dead(card); continue; } memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_APP_CMD; cmd.arg = card->rca << 16; cmd.flags = MMCSD_RSP1; err = mmc_wait_for_cmd(host, &cmd, 0); if ((err != MMC_ERR_NONE) || !(cmd.resp[6] & R1_APP_CMD)) { mmc_card_set_dead(card); continue; } memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = SD_APP_SEND_SCR; cmd.arg = 0; cmd.flags = MMCSD_RSP1;#if 0 memset(&data, 0, sizeof(struct mmc_data)); data.timeout_ns = card->csd.tacc_ns * 10; data.timeout_clks = card->csd.tacc_clks * 10; data.blksz_bits = 3; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; data.sg_len = 1; memset(&mrq, 0, sizeof(struct mmc_request)); mrq.cmd = &cmd; mrq.data = &data;#endif#if 1 mmc_debug_msg("card->rca : %x\n",card->rca); host->src_data(host, &mrq ,&(card->rca),scr_reg); card->raw_scr[0] = (scr_reg[0] << 8) | scr_reg[1]; card->raw_scr[1] = (scr_reg[2] << 8) | scr_reg[3]; card->raw_scr[2] = (scr_reg[4] << 8) | scr_reg[5]; card->raw_scr[3] = (scr_reg[6] << 8) | scr_reg[7]; mmc_debug_msg("card->raw_scr[0] : %x\n",card->raw_scr[0]); mmc_debug_msg("card->raw_scr[1] : %x\n",card->raw_scr[1]); mmc_debug_msg("card->raw_scr[2] : %x\n",card->raw_scr[2]); mmc_debug_msg("card->raw_scr[3] : %x\n",card->raw_scr[3]); if (card->raw_scr[0]&0x1)#endif host->caps = MMC_CAP_4_BIT_DATA; mmc_decode_scr(card); } mmc_deselect_cards(host);}static unsigned int mmc_calculate_clock(struct mmc_host *host){ struct mmc_card *card; unsigned int max_dtr = host->f_max; list_for_each_entry(card, &host->cards, node) if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr) max_dtr = card->csd.max_dtr; DBG("MMC: selected %d.%03dMHz transfer rate\n", max_dtr / 1000000, (max_dtr / 1000) % 1000); host->change_clk25m(); return max_dtr;}/* * Check whether cards we already know about are still present. * We do this by requesting status, and checking whether a card * responds. * * A request for status does not cause a state change in data * transfer mode. */static void mmc_check_cards(struct mmc_host *host){ struct list_head *l, *n; mmc_deselect_cards(host); list_for_each_safe(l, n, &host->cards) { struct mmc_card *card = mmc_list_to_card(l); struct mmc_command cmd; int err; cmd.opcode = MMC_SEND_STATUS; cmd.arg = card->rca << 16; cmd.flags = MMCSD_RSP1; err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err == MMC_ERR_NONE) continue; mmc_card_set_dead(card); }}static void mmc_setup(struct mmc_host *host){ if (host->ios.power_mode != MMC_POWER_ON) { int err; u32 ocr; host->mode = MMC_MODE_SD; mmc_power_up(host); mmc_idle_cards(host); err = mmc_send_app_op_cond(host, 0, &ocr); /* * If we fail to detect any SD cards then try * searching for MMC cards. */ if (err != MMC_ERR_NONE) { printk ("Searching for MMC card\n"); host->mode = MMC_MODE_MMC; err = mmc_send_op_cond(host, 0, &ocr); if (err != MMC_ERR_NONE) return; } printk("ocr=%d\n",(int)ocr); host->ocr = ocr;//mmc_select_voltage(host, ocr); //printk ("host->ocr : %x\n",host->ocr); /* * Since we're changing the OCR value, we seem to * need to tell some cards to go back to the idle * state. We wait 1ms to give cards time to * respond. */ if (host->ocr) mmc_idle_cards(host); } else { host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.clock = host->f_min; host->ops->set_ios(host, &host->ios); /* * We should remember the OCR mask from the existing * cards, and detect the new cards OCR mask, combine * the two and re-select the VDD. However, if we do * change VDD, we should do an idle, and then do a * full re-initialisation. We would need to notify * drivers so that they can re-setup the cards as * well, while keeping their queues at bay. * * For the moment, we take the easy way out - if the * new cards don't like our currently selected VDD, * they drop off the bus. */ } if (host->ocr == 0){ return; } if( host->mode == MMC_MODE_SD ) cardtype = 0; else cardtype = 1; /* * Send the selected OCR multiple times... until the cards * all get the idea that they should be ready for CMD2. * (My SanDisk card seems to need this.) */ if (host->mode == MMC_MODE_SD) mmc_send_app_op_cond(host, host->ocr, NULL); else mmc_send_op_cond(host, host->ocr, NULL); mmc_discover_cards(host); /* * Ok, now switch to push-pull mode. */ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; host->ops->set_ios(host, &host->ios); mmc_read_csds(host); if (host->mode == MMC_MODE_SD){ mmc_disable_pull_up(host); mmc_read_scrs(host); }}/** * mmc_detect_change - process change of state on a MMC socket * @host: host which changed state. * @delay: optional delay to wait before detection (jiffies) * * All we know is that card(s) have been inserted or removed * from the socket(s). We don't know which socket or cards. */void mmc_detect_change(struct mmc_host *host, unsigned long delay){ printk("mmc_detect_change\n"); if (delay) schedule_delayed_work(&host->detect, delay); else schedule_work(&host->detect);}EXPORT_SYMBOL(mmc_detect_change);static void mmc_rescan(void *data){ struct mmc_host *host = data; struct list_head *l, *n; mmc_claim_host(host); mmc_debug_msg ("host->ios.power_mode : %x\n",host->ios.power_mode); printk("mmc_rescan\n"); if (host->ios.power_mode == MMC_POWER_ON){ printk("host->ios.power_mode == MMC_POWER_ON\n"); mmc_check_cards(host); } printk("mmc_rescan1\n"); mmc_setup(host); if (!list_empty(&host->cards)) { /* * (Re-)calculate the fastest clock rate which the * attached cards and the host support. */ host->ios.clock = mmc_calculate_clock(host); host->ops->set_ios(host, &host->ios); } mmc_release_host(host); list_for_each_safe(l, n, &host->cards) { struct mmc_card *card = mmc_list_to_card(l); /* * If this is a new and good card, register it. */ if (!mmc_card_present(card) && !mmc_card_dead(card)) { if (mmc_register_card(card)){ mmc_card_set_dead(card); } else{ action = 0; mmc_card_set_present(card); } } /* * If this card is dead, destroy it. */ if (mmc_card_dead(card)) { list_del(&card->node); mmc_remove_card(card); action = 1; } } /* * If we discover that there are no cards on the * bus, turn off the clock and power down. */ if (list_empty(&host->cards)){ mmc_power_off(host); action = 1; }}/** * mmc_alloc_host - initialise the per-host structure. * @extra: sizeof private data structure * @dev: pointer to host device model structure * * Initialise the per-host structure. */struct mmc_host *mmc_alloc_host(int extra, struct device *dev){ struct mmc_host *host; host = mmc_alloc_host_sysfs(extra, dev); if (host) { spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_LIST_HEAD(&host->cards); INIT_WORK(&host->detect, mmc_rescan, host); /* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities. */ host->max_hw_segs = 1; host->max_phys_segs = 1; host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9); host->max_seg_size = PAGE_CACHE_SIZE; } return host;}EXPORT_SYMBOL(mmc_alloc_host);/** * mmc_add_host - initialise host hardware * @host: mmc host */int mmc_add_host(struct mmc_host *host){ int ret; ret = mmc_add_host_sysfs(host); //if (ret == 0) { if (ret == -1) { mmc_power_off(host); mmc_detect_change(host, 0); } return ret;}EXPORT_SYMBOL(mmc_add_host);/** * mmc_remove_host - remove host hardware * @host: mmc host * * Unregister and remove all cards associated with this host, * and power down the MMC bus. */void mmc_remove_host(struct mmc_host *host){ struct list_head *l, *n; list_for_each_safe(l, n, &host->cards) { struct mmc_card *card = mmc_list_to_card(l); mmc_remove_card(card); } mmc_power_off(host); mmc_remove_host_sysfs(host);}EXPORT_SYMBOL(mmc_remove_host);/** * mmc_free_host - free the host structure * @host: mmc host * * Free the host once all references to it have been dropped. */void mmc_free_host(struct mmc_host *host){ flush_scheduled_work(); mmc_free_host_sysfs(host);}EXPORT_SYMBOL(mmc_free_host);#ifdef CONFIG_PM/** * mmc_suspend_host - suspend a host * @host: mmc host * @state: suspend mode (PM_SUSPEND_xxx) */int mmc_suspend_host(struct mmc_host *host, pm_message_t state){ mmc_debug_msg ("%s CALLED \n",__FUNCTION__); mmc_claim_host(host); mmc_deselect_cards(host); mmc_power_off(host); mmc_release_host(host); return 0;}EXPORT_SYMBOL(mmc_suspend_host);/** * mmc_resume_host - resume a previously suspended host * @host: mmc host */int mmc_resume_host(struct mmc_host *host){ mmc_detect_change(host, 0); return 0;}EXPORT_SYMBOL(mmc_resume_host);#endifstatic int mmc_sd_proc_read(char * page, char ** start, off_t offset, int count, int * eof, void * data){ int length = 0; if ( action == 0 ) length += sprintf( page+length, "%s", "add" ); else /* action == remove */ length += sprintf( page+length, "%s", "remove" ); if ( cardtype == 0 ) length += sprintf( page+length, "%s\n", "sd" ); else length += sprintf( page+length, "%s\n", "mmc" ); *eof = 1; return length;}static proc_mmc_sd_init( void ){ create_proc_read_entry( "mmc_sd", 0, 0, mmc_sd_proc_read, (void *)NULL );}static int __init mmc_init(void){ proc_mmc_sd_init(); return 0;}static void __exit mmc_exit(void){ return;}module_init(mmc_init);module_exit(mmc_exit);MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card driver");MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -