📄 mss_core.c
字号:
card->prot_driver->detach_card(card); card->prot_driver = NULL; card->state &= ~MSS_CARD_INITED; } return 0;}/* * After knowing a card has been ejected from the slot, this function should * be invoked. At last, unload card driver in card(done by card_driver->remove). */static int mss_eject_card(struct mss_card *card){ BUG_ON(!card); __mss_eject_card(card); card->slot->card = NULL; card->slot = NULL; return 0;}unsigned int mss_get_capacity(struct mss_card *card){ int ret; u32 cap; mss_claim_host(card->slot->host, card); ret = card->prot_driver->prot_entry(card, MSS_GET_CAPACITY, NULL, &cap); mss_release_host(card->slot->host); if (ret) cap = 0; return cap;}int mss_scan_slot(struct mss_slot *slot){ struct mss_card *card; struct mss_host *host; int ret = 0; card = slot->card; host = slot->host; if (card) printk(KERN_INFO "mss_scan_slot card_type is %d\n", card->card_type); dbg("before scan:host:%d, slot:%d", host->id, slot->id); down(&slot->scan); /* slot has card in it before, and the card is resuming back */ if (card && (card->state & MSS_CARD_SUSPENDED)) { /* card was ejected when it is suspended */ if (host->ops->is_slot_empty && host->ops->is_slot_empty(slot)) { card->state |= MSS_CARD_REMOVING; ret = MSS_ERROR_CARD_REMOVING; } else { /* * if host provides is_slot_empty, and it * indicates that the card is in slot, then * we try to init it. * else, we try to init it directly. Obvisouly * that if there is no card in the slot, the * init will fail */ ret = mss_init_card(card); if (ret == MSS_ERROR_MISMATCH_CARD) card->state |= MSS_CARD_INVALID; } } else if (card && (card->state & MSS_CARD_INVALID)) { card->state &= ~MSS_CARD_INVALID; ret = mss_eject_card(card); if (!host->ops->is_slot_empty || (host->ops->is_slot_empty && !host->ops->is_slot_empty(slot))) { ret = mss_insert_card(slot); } } /* slot has card in it before, and no suspend happens */ else if (card && (card->state & MSS_CARD_REGISTERED)) { if (host->ops->is_slot_empty) { /* card has been ejected */ if (host->ops->is_slot_empty(slot)) ret = mss_eject_card(card); } else { /* * We try to send the status query command. * If card->state has set MSS_CARD_REGISRTEED, * it indicates that the card has finished * identification process, and it will response * the SEND_STATUS command. */ if (mss_query_card(card)) /* Card has been ejected */ ret = mss_eject_card(card); } } /* slot has card in it, but the card is not registered */ else if (card) { /* This should never be happens, because when insert fail, * we will delete the card */ BUG(); } /* slot has no card in it before */ else if (!card) { if (host->ops->is_slot_empty) { /* slot is not empty */ if (!host->ops->is_slot_empty(slot)) ret = mss_insert_card(slot); } else { /* * try to insert a card */ ret = mss_insert_card(slot); } } else { printk(KERN_ERR "Unexpected situation when scan host:%d" ", slot:%d, card state:0x%x\n", host->id, slot->id, card ? card->state : 0x0); BUG(); } up(&slot->scan); dbg("after scan, host:%d, slot:%d", host->id, slot->id); return ret;}void mss_scan_host(struct mss_host *host){ struct mss_slot *slot; int i; for (i = 0; i < host->slot_num; i++) { slot = &host->slots[i]; mss_scan_slot(slot); }}void mss_force_card_remove(struct mss_card *card){ mss_eject_card(card);}static void mss_wait_done(struct mss_ll_request *llreq){ complete(llreq->done_data);}int mss_send_ll_req(struct mss_host *host, struct mss_ll_request *llreq){ DECLARE_COMPLETION(complete); llreq->done = mss_wait_done; llreq->done_data = &complete; llreq->cmd->llreq = llreq; llreq->cmd->error = MSS_ERROR_NONE; if (llreq->data) llreq->cmd->data = llreq->data; host->ops->request(host, llreq); wait_for_completion(&complete); dbg("CMD 0x%x, return error: %d", llreq->cmd->opcode, llreq->cmd->error); return llreq->cmd->error;}int mss_send_simple_ll_req(struct mss_host *host, struct mss_ll_request *llreq, struct mss_cmd *cmd, u32 opcode, u32 arg, u32 rtype, u32 flags){ memset(llreq, 0x0, sizeof(struct mss_ll_request)); memset(cmd, 0x0, sizeof(struct mss_cmd)); cmd->opcode = opcode; cmd->arg = arg; cmd->rtype = rtype; cmd->flags = flags; llreq->cmd = cmd; return mss_send_ll_req(host, llreq);} /* * add controller into mss_host_list */int register_mss_host(struct mss_host *host){ list_add_tail(&host->node, &mss_host_list); mss_power_off(host); mss_power_up(host); mss_idle_cards(host); return 0;}/* * delete controller from mss_controller_list */void unregister_mss_host(struct mss_host *host){ list_del(&host->node);}/***************************************************************************** * * functions for protocol driver * ****************************************************************************//* * add protocol driver into mss_protocol_list */int register_mss_prot_driver(struct mss_prot_driver *drv){ struct list_head *item; struct mss_host *host; struct mss_slot *slot; int i; list_add(&drv->node, &mss_protocol_list); list_for_each(item, &mss_host_list) { host = list_entry(item, struct mss_host, node); for (i = 0; i < host->slot_num; i++) { slot = &host->slots[i]; if (!slot->card) mss_scan_slot(slot); } } return 0;}/* * delete protocol driver from mss_protocol_list */void unregister_mss_prot_driver(struct mss_prot_driver *drv){ struct mss_slot *slot; struct list_head *item; struct mss_host *host; int i; list_del(&drv->node); list_for_each(item, &mss_host_list) { host = list_entry(item, struct mss_host, node); for (i = 0; i < host->slot_num; i++) { slot = &host->slots[i]; if (slot->card && slot->card->prot_driver == drv) mss_eject_card(slot->card); } }}/***************************************************************************** * * interfaces for card driver * ****************************************************************************//* * register card driver onto MMC bus */int register_mss_driver (struct mss_driver *drv){ dbg("register mss driver :%s\n", drv->driver.name); drv->driver.bus = &mmc_bus_type; return driver_register(&drv->driver); /* will call card_driver->probe */}/* * unregister card driver from MMC bus */void unregister_mss_driver (struct mss_driver *drv){ driver_unregister(&drv->driver);}/* * enable SDIO interrupt, used by SDIO application driver */void mss_set_sdio_int(struct mss_host *host, int sdio_en){ host->ops->enable_sdio_int(host, sdio_en);}void mss_set_clock(struct mss_host *host, int clock){ struct mss_ios ios; memcpy(&ios, &host->ios, sizeof(ios)); if (clock > host->f_max) clock = host->f_max; else if (clock < host->f_min) clock = host->f_min; ios.clock = clock; host->ops->set_ios(host, &ios);}void mss_set_buswidth(struct mss_host *host, int buswidth){ struct mss_ios ios; memcpy(&ios, &host->ios, sizeof(ios)); ios.bus_width = buswidth; host->ops->set_ios(host, &ios);}void mss_set_busmode(struct mss_host *host, int busmode){ struct mss_ios ios; memcpy(&ios, &host->ios, sizeof(ios)); ios.bus_mode = busmode; host->ops->set_ios(host, &ios);}int mss_send_request(struct mss_request *req){ struct mss_host *host; struct mss_card *card; int ret; if (!req->card || !req->card->slot) return -ENODEV; card = req->card; host = card->slot->host; if (req->card->state & MSS_CARD_REMOVING) return MSS_ERROR_CARD_REMOVING; card->state |= MSS_CARD_HANDLEIO; mss_claim_host(host, card); ret = card->prot_driver->prot_entry(card, req->action, req->arg, req->result); mss_release_host(host); card->state &= ~MSS_CARD_HANDLEIO; if (ret) req->errno = card->prot_driver->get_errno(card); dbg("Request for action :%d, protolcol :%s return error :%d", req->action, card->prot_driver->name, req->errno); return ret;}struct mss_host * mss_alloc_host(unsigned int slot_num, unsigned int id, unsigned int private_size){ struct mss_host *host; int i = 0, size; size = sizeof(struct mss_host) + sizeof(struct mss_slot) * slot_num + private_size; host = (struct mss_host *)kzalloc(size, GFP_KERNEL); if (!host) return NULL; host->id = id; host->slot_num = slot_num; while(i < slot_num) { host->slots[i].id = i; host->slots[i].host = host; init_MUTEX(&host->slots[i].scan); i++; } host->private = (void *)&host->slots[slot_num]; host->active_card = NULL; init_waitqueue_head(&host->wq); return host;}void mss_free_host(struct mss_host *host){ kfree(host); }struct mss_host *mss_find_host(int id){ struct list_head *pos; struct mss_host *host; list_for_each(pos, &mss_host_list) { host = list_entry(pos, struct mss_host, node); if (host->id == id) return host; } return NULL;}/***************************************************************************** * * module init and exit functions * ****************************************************************************/static int mss_core_driver_init(void){ return bus_register(&mmc_bus_type);}static void mss_core_driver_exit(void){ bus_unregister(&mmc_bus_type);}EXPORT_SYMBOL(mss_scan_slot);EXPORT_SYMBOL(mss_scan_host);EXPORT_SYMBOL(mss_alloc_host);EXPORT_SYMBOL(mss_free_host);EXPORT_SYMBOL(mss_find_host);EXPORT_SYMBOL(mss_force_card_remove);EXPORT_SYMBOL(register_mss_host);EXPORT_SYMBOL(unregister_mss_host);EXPORT_SYMBOL(register_mss_driver);EXPORT_SYMBOL(unregister_mss_driver);EXPORT_SYMBOL(mss_send_request);EXPORT_SYMBOL(mss_get_capacity);EXPORT_SYMBOL(register_mss_prot_driver);EXPORT_SYMBOL(unregister_mss_prot_driver);EXPORT_SYMBOL(mss_send_ll_req);EXPORT_SYMBOL(mss_send_simple_ll_req);EXPORT_SYMBOL(mss_set_sdio_int);EXPORT_SYMBOL(mss_set_buswidth);EXPORT_SYMBOL(mss_set_clock);EXPORT_SYMBOL(mss_set_busmode);EXPORT_SYMBOL(mss_init_card);EXPORT_SYMBOL(mss_card_get);EXPORT_SYMBOL(mss_card_put);module_init(mss_core_driver_init);module_exit(mss_core_driver_exit);MODULE_AUTHOR("Chao Xie");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Core driver for MMC/SD/SDIO card");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -