小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Linux SD卡驅(qū)動開發(fā)(五)

 WUCANADA 2016-04-06

一、工作流程

mmc驅(qū)動主要文件包括

drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/

內(nèi)核啟動時,首先執(zhí)行core/core.c的mmc_init,注冊mmc、sd總線,以及一個host class設(shè)備。接著執(zhí)行card/block.c中,申請一個塊設(shè)備。

二、數(shù)據(jù)結(jié)構(gòu):

這里涉及三種總線

1. platform bus //MMC host controller 作為一種 platform device, 它是需要注冊到 platform bus上 的  
driver/base/platform.c  
struct bus_type platform_bus_type = {  
    .name        = "platform",  
    .dev_attrs    = platform_dev_attrs,  
    .match        = platform_match,  
    .uevent        = platform_uevent,  
    .pm        = &platform_dev_pm_ops,  
};  
  
2. mmc bus type  //在mmc_init()中被創(chuàng)建的.通過調(diào)用 mmc_register_bus() 來注冊 MMC 總線  
drivers\mmc\core\bus.c  
static struct bus_type mmc_bus_type = {  
    .name        = "mmc",  
    .dev_attrs    = mmc_dev_attrs,  
    .match        = mmc_bus_match,  
    .uevent        = mmc_bus_uevent,  
    .probe        = mmc_bus_probe,  
    .remove        = mmc_bus_remove,  
    .shutdown        = mmc_bus_shutdown,  
    .pm        = &mmc_bus_pm_ops,  
};  
  
3. sdio bus type    //在mmc_init()中被創(chuàng)建的.通過調(diào)用sdio_register_bus() 來注冊 SDIO 總線  
drivers\mmc\core\sdio_bus.c  
static struct bus_type sdio_bus_type = {  
    .name        = "sdio",  
    .dev_attrs    = sdio_dev_attrs,  
    .match        = sdio_bus_match,  
    .uevent        = sdio_bus_uevent,  
    .probe        = sdio_bus_probe,  
    .remove        = sdio_bus_remove,  
    .pm        = SDIO_PM_OPS_PTR,  
};  

     其中mmc總線操作相關(guān)函數(shù),由于mmc卡支持多種總數(shù)據(jù)線,如SPI、SDIO、8LineMMC而不同的總線的操作控制方式不盡相同,所以通過此結(jié)構(gòu)與相應(yīng)的總線回調(diào)函數(shù)相關(guān)聯(lián)。

//總線操作結(jié)構(gòu)
struct mmc_bus_ops {
    void (*remove)(struct mmc_host *);
    void (*detect)(struct mmc_host *);
    int (*sysfs_add)(struct mmc_host *, struct mmc_card *card);
    void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card);
    void (*suspend)(struct mmc_host *);
    void (*resume)(struct mmc_host *);
};
//  mmc卡的總線操作 core/mmc.c
static const struct mmc_bus_ops mmc_ops = {
    .remove = mmc_remove,
    .detect = mmc_detect,
    .sysfs_add = mmc_sysfs_add,
    .sysfs_remove = mmc_sysfs_remove,
    .suspend = mmc_suspend,
    .resume = mmc_resume,
};
// sd卡的總線操作 core/sd.c
static const struct mmc_bus_ops mmc_sd_ops = {
    .remove = mmc_sd_remove,
    .detect = mmc_sd_detect,
    .sysfs_add = mmc_sd_sysfs_add,
    .sysfs_remove = mmc_sd_sysfs_remove,
    .suspend = mmc_sd_suspend,
    .resume = mmc_sd_resume,
};
// sdio的總線操作 core/sdio.c
static const struct mmc_bus_ops mmc_sdio_ops = {
    .remove = mmc_sdio_remove,
    .detect = mmc_sdio_detect,
};

關(guān)于總線操作的函數(shù):

.detect,驅(qū)動程序經(jīng)常需要調(diào)用此函數(shù)去檢測mmc卡的狀態(tài),具體實現(xiàn)是發(fā)送CMD13命令,并讀回響應(yīng),如果響應(yīng)錯誤,則依次調(diào)用.remove、detach_bus來移除卡及釋放總線。

三、總體架構(gòu)

1、kernel啟動時,先后執(zhí)行mmc_init()及mmc_blk_init(),以對mmc設(shè)備及mmc塊模塊進行初始化

mmc/core/core.c  
static int __init mmc_init(void)  
    workqueue = alloc_ordered_workqueue("kmmcd", 0);//建立了一個工作隊列workqueue,這個工作隊列的作用主要是用來支持熱插拔  
    ret = mmc_register_bus();//注冊一個mmc總線  
    ret = mmc_register_host_class();//注冊了一個 mmc_host 類  
    ret = sdio_register_bus();//注冊了一個 sdio_bus_type  
      
*******   
mmc/card/block.c  
static int __init mmc_blk_init(void)  
    res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");//注冊一個塊設(shè)備  
    res = mmc_register_driver(&mmc_driver);//注冊一個mmc設(shè)備驅(qū)動  
  
static struct mmc_driver mmc_driver =  
    .probe      = mmc_blk_probe,  
      
static int mmc_blk_probe(struct mmc_card *card)  
    mmc_set_bus_resume_policy(card->host, 1);//*host 該指針指向一個mmc主機實例,塊設(shè)備中的讀寫操作就是調(diào)用這個mmc主機的操作函數(shù)host->ops->request來實現(xiàn)對實際硬件的操作。  

2、core部分會做兩件事

a -- 取得總線

b -- 檢查總線操作結(jié)構(gòu)指針bus_ops,如果為空,則重新利用各總線對端口進行掃描,檢測順序依次為:SDIO、Normal SD、MMC。當(dāng)檢測到相應(yīng)的卡類型后,就使用mmc_attach_bus()把相對應(yīng)的總線操作與host連接起來

void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
    ...
    host->bus_ops = ops;
    ...
}

3、然后在掛載mmc設(shè)備驅(qū)動時,執(zhí)行驅(qū)動程序中的xx_mmc_probe(),檢測host設(shè)備中掛載的sd設(shè)備

kernel\arch\arm\configs\msm9625_defconfig  
CONFIG_MMC_MSM=y  
  
kernel\drivers\mmc\host\Makefile  
obj-(CONFIG_MMC_MSM)        += msm_sdcc.o      
  
msm_sdcc.c (drivers\mmc\host)  
//系統(tǒng)初始化時掃描 platform 總線上是否有名為該SD主控制器名字"msm_sdcc"的設(shè)備,如果有, 驅(qū)動程序?qū)⒅骺刂破鲯燧d到 platform 總線上,并注冊該驅(qū)動程序  
static int __init msmsdcc_init(void)  
    platform_driver_register(&msmsdcc_driver);    //注冊 platform driver  
      
static struct platform_driver msmsdcc_driver = {  
    .probe        = msmsdcc_probe,  
    .remove        = msmsdcc_remove,  
    .driver        = {  
        .name    = "msm_sdcc",  
        .pm    = &msmsdcc_dev_pm_ops,  
        .of_match_table = msmsdcc_dt_match,  
    },  
};      
      
//整個設(shè)備驅(qū)動的 probe()函數(shù),其本質(zhì)就是是為設(shè)備建立起數(shù)據(jù)結(jié)構(gòu)并對其賦初值  
//msmsdcc_probe 所有賦值中,我們重點關(guān)注從 platform_device *pdev里得到的數(shù)據(jù),即設(shè)備樹里的數(shù)據(jù)  
//platform_device *pdev是在系統(tǒng)初始化的時候掃描 platform 總線發(fā)現(xiàn)SD主控制器后所得到的數(shù)據(jù)  
static int msmsdcc_probe(struct platform_device *pdev)      
{      
    //初始化設(shè)備的數(shù)據(jù)結(jié)構(gòu)  
    if (pdev->dev.of_node) {  
    plat = msmsdcc_populate_pdata(&pdev->dev);        //獲取設(shè)備樹信息  
    of_property_read_u32((&pdev->dev)->of_node,"cell-index", &pdev->id);  
    } else {  
        plat = pdev->dev.platform_data;  
    }  
    //為主設(shè)備控制器建立數(shù)據(jù)結(jié)構(gòu),建立kobject,并初始化等待隊列,工作隊列,以及一些控制器的配置  
    mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);            ---- 1  
    //實現(xiàn)設(shè)備驅(qū)動的功能函數(shù),如mmc->ops = &pxamci_ops;  
    mmc->ops = &msmsdcc_ops;  
    //申請中斷函數(shù) request_irq()  
    ret = request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED,DRIVER_NAME " (cmd)", host);  
    //注冊設(shè)備,即注冊kobject,建立sys文件,發(fā)送uevent等  
    mmc_add_host(mmc);                                                        ---- 2  
    //其他需求,如在/proc/driver下建立用戶交互文件等  
    ret = device_create_file(&pdev->dev, &host->auto_cmd21_attr);  
}      

4、此時probe函數(shù)會創(chuàng)建一個host設(shè)備,然后開啟一個延時任務(wù)mmc_rescan()。

1:    
core/host.c   
//重要函數(shù)mmc_alloc_host , 用于分配mmc_host結(jié)構(gòu)體指針的內(nèi)存空間大小  
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)----創(chuàng)建一個 mmc_host 和 mmc_spi_host ,且mmc_host的最后一個成員指針private指向mmc_spi_host  
    //建立數(shù)據(jù)結(jié)構(gòu)  
    struct mmc_host *host;    
    host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);  
    //建立kobject  
    host->parent = dev;  
    host->class_dev.parent = dev;  
    host->class_dev.class = &mmc_host_class;  
    device_initialize(&host->class_dev);  
    //初始化等待隊列,工作隊列  
    init_waitqueue_head(&host->wq);  
    INIT_DELAYED_WORK(&host->detect, mmc_rescan);    //建立了一個工作隊列任務(wù) structdelayed_work detect。工作隊列任務(wù)執(zhí)行的函數(shù)為mmc_rescan  
    //配置控制器  
    host->max_segs = 1;  
    host->max_seg_size = PAGE_CACHE_SIZE;  
    return host;  

5、驅(qū)動掛載成功后,mmc_rescan()函數(shù)被執(zhí)行,然后對卡進行初始化(步驟后面詳細(xì)講述)

core/core.c  
//mmc_rescan 函數(shù)是需要重點關(guān)注的,因為SD卡協(xié)議中的檢測,以及卡識別等都是在此函數(shù)中實現(xiàn)  
void mmc_rescan(struct work_struct *work)  
    if (host->bus_ops && host->bus_ops->detect && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE))    //存在熱插拔卡,不包括emmc,調(diào)用探測函數(shù)  
    host->bus_ops->detect(host);  
    mmc_bus_put(host);    //減少引用技術(shù),就釋放  
    mmc_bus_get(host);    //增加bus引用計數(shù)  
    if (host->bus_ops != NULL) {  
        mmc_bus_put(host);    //如果卡仍然存在,減少引用計數(shù),不必探測了  
        goto out;  
    }  
    if (host->ops->get_cd && host->ops->get_cd(host) == 0)  //有卡,退出  
    goto out;  
    mmc_claim_host(host);                   //用于檢測host是否被占用,占用則退出,否則標(biāo)記成占用  
      
    if (!mmc_rescan_try_freq(host, host->f_min))  

初始化卡接以下流程初始化:

a、發(fā)送CMD0使卡進入IDLE狀態(tài)
b、發(fā)送CMD8,檢查卡是否SD2.0。SD1.1是不支持CMD8的,因此在SD2.0 Spec中提出了先發(fā)送CMD8,如響應(yīng)為無效命令,則卡為SD1.1,否則就是SD2.0(請參考SD2.0 Spec)。
c、發(fā)送CMD5讀取OCR寄存器。
d、發(fā)送ACMD55、CMD41,使卡進入工作狀態(tài)。MMC卡并不支持ACMD55、CMD41,如果這步通過了,則證明這張卡是SD卡。
e、如果d步驟錯誤,則發(fā)送CMD1判斷卡是否為MMC。SD卡不支持CMD1,而MMC卡支持,這就是SD和MMC類型的判斷依據(jù)。
f、如果ACMD41和CMD1都不能通過,那這張卡恐怕就是無效卡了,初始化失敗。

      假如掃描到總線上掛有有效的設(shè)備,就調(diào)用相對應(yīng)的函數(shù)把設(shè)備裝到系統(tǒng)中,mmc_attach_sdio()、mmc_attach_sd()、mmc_attach_mmc()這三個函數(shù)分別是裝載sdio設(shè)備,sd卡和mmc卡的。

     在 sd卡中,驅(qū)動循環(huán)發(fā)送ACMD41、CMD55給卡,讀取OCR寄存器,成功后,依次發(fā)送CMD2(讀CID)、CMD3(得到RCA)、CMD9(讀 CSD)、CMD7(選擇卡)。后面還有幾個命令分別是ACMD41&CMD51,使用CMD6切換一些功能,如切換到高速模式。

     經(jīng)過上述步驟,已經(jīng)確定當(dāng)前插入的卡是一張有效、可識別的存儲卡。然后調(diào)用mmc_add_card()把存儲卡加到系統(tǒng)中。正式與系統(tǒng)驅(qū)動連接在一起

static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)  
    host->f_init = freq;                 //設(shè)置某一個時鐘頻率  
    mmc_power_up(host);                     //與 mmc_power_off 類似,不過設(shè)置了啟動時需要的 ios  
    mmc_go_idle(host);          ----1a      //CMD0 ,SD卡從 inactive 到 idle          
    mmc_send_if_cond(host, host->ocr_avail);//檢測SD卡是否支持SD2.0       
    if (!mmc_attach_sd(host))   ----1b      //然后對mmc或者sd發(fā)送一些命令進行探測,這里以 sd 為例  
  
1a:  
int mmc_go_idle(struct mmc_host *host)    
    struct mmc_command cmd = {0};  
    cmd.opcode = MMC_GO_IDLE_STATE; //即CMD0  
    cmd.arg = 0;                    //此命令無參數(shù)  
    err = mmc_wait_for_cmd(host, &cmd, 0)  
      
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)  
    memset(cmd->resp, 0, sizeof(cmd->resp));  //調(diào)用了 mmc_start_request,   
    cmd->retries = retries;  
    mrq.cmd = cmd;                                
    mmc_wait_for_req(host, &mrq);  
      
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)   ----重要函數(shù)  
    __mmc_start_req(host, mrq);  
  
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)  
    mmc_start_request(host, mrq);  
          
static void mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)  
    host->ops->request(host, mrq);    //即 msmsdcc_request, MMC 核心與核HOST 層握手了  
  
      
1b:   
core/mmc.c  
int mmc_attach_sd(struct mmc_host *host)                    //完成匹配,和初始化卡的功能  
    err = mmc_send_app_op_cond(host, 0, &ocr);      ----1b1 //檢測是否是支持SD卡  
    host->ocr = mmc_select_voltage(host, ocr);               //設(shè)置MMC電壓  
    err = mmc_init_card(host, host->ocr, NULL);              //對mmc卡進行初始化,主要是讀取mmc卡里的一些寄存器信息,且對這些寄存器的值進行設(shè)置  
    err = mmc_sd_init_card(host, host->ocr, NULL);   ----1b2  
    err = mmc_add_card(host->card);                  ----1b3 //調(diào)用 mmc_add_card 來把 mmc_card 掛載到 mmc_bus_type 總線去  
      
      
1b1:  
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)  
    cmd.opcode = SD_APP_OP_COND;    //ACMD41,獲取 SDcard 的允許電壓范圍值,保存在 ocr 中. 所有發(fā)送它之前需要發(fā)送 CMD_55 命令。執(zhí)行完后 card 狀態(tài)變?yōu)?READY  
  
      
      
1b2:  
static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,struct mmc_card *oldcard)  
    err = mmc_sd_get_cid(host, ocr, cid, &rocr);        //發(fā)送 CMD2 ,獲取卡的身份信息,進入到身份狀態(tài)  
    card = mmc_alloc_card(host, &sd_type);              //分配一張 SD 類型的 card 結(jié)構(gòu)  
    err = mmc_send_relative_addr(host, &card->rca);      //獲取卡的相對地址,注意一前卡和主機通信都采用默認(rèn)地址,現(xiàn)在有了自己的地址了,進入到 stand_by 狀態(tài)  
    err = mmc_sd_get_csd(host, card); ----mmc_send_csd(card, card->raw_csd);//CMD9, 獲取 CSD 寄存器的信息,包括 block 長度,卡容量等信息  
    err = mmc_select_card(card);                        //發(fā)送 CMD7, 選中目前 RADD 地址上的卡,任何時候總線上只有一張卡被選中,進入了傳輸狀態(tài)   
    err = mmc_sd_setup_card(host, card, oldcard != NULL);     
  
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,bool reinit)  
    mmc_app_send_scr(card, card->raw_scr);   //發(fā)送命令 ACMD51 獲取 SRC 寄存器的內(nèi)容,進入到 SENDING-DATA 狀態(tài)  
    if (host->ops->get_ro(host) > 0 )      // get_ro(host) 即是 msmsdcc_get_ro   
        mmc_card_set_readonly(card);        //是否寫保護,如果是的,將 card 狀態(tài)設(shè)置為只讀狀態(tài)  
      
1b3:  
core/bus.c  
int mmc_add_card(struct mmc_card *card)     //  /sys/devices/msm_sdcc.2/mmc_host/mmc0  
    ret = device_add(&card->dev);  
  
drivers/base/core.c  
int device_add(struct device *dev)  
    dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); //  
    bus_probe_device(dev);  
  
void bus_probe_device(struct device *dev)  
        if (bus->p->drivers_autoprobe)   
        ret = device_attach(dev);           //這樣,在總線 mmc_bus_type 中就有了 mmc 設(shè)備 mmc_card 了      
      
      
***********   
2:  
//完成kobject的注冊,并調(diào)用 mmc_rescan,目的在于在系統(tǒng)初始化的時候就掃描SD總線查看是否存在SD卡  
int mmc_add_host(struct mmc_host *host)  
    err = device_add(&host->class_dev);//將設(shè)備注冊進linux設(shè)備模型,最終的結(jié)果就是在 sys/bus/platform/devices 目錄下能見到 mmc 設(shè)備節(jié)點  
    mmc_start_host(host);  
      
      
void mmc_start_host(struct mmc_host *host)    
    mmc_power_off(host);                ----2a  
    mmc_detect_change(host, 0);         ----2b  
  
2a:  
void mmc_power_off(struct mmc_host *host)     
    host->ios.power_mode = MMC_POWER_OFF;    //對 ios 進行了設(shè)置  
    ...  
    mmc_set_ios(host);  
  
void mmc_set_ios(struct mmc_host *host)  
    host->ops->set_ios(host, ios);            // set_ios 實際上就是 mmc_host_ops 的 .set_ios  = msmsdcc_set_ios,  
  
2b:  
void mmc_detect_change(struct mmc_host *host, unsigned long delay)  
        mmc_schedule_delayed_work(&host->detect, delay); //實際上就是調(diào)用我們前面說的延時函數(shù) mmc_rescan  

6、卡設(shè)備加到系統(tǒng)中后,通知mmc塊設(shè)備驅(qū)動。塊設(shè)備驅(qū)動此時調(diào)用probe函數(shù),即mmc_blk_probe()函數(shù),mmc_blk_probe()首 先分配一個新的mmc_blk_data結(jié)構(gòu)變量,然后調(diào)用mmc_init_queue,初始化blk隊列。然后建立一個線程 mmc_queue_thread()

7、然后就可以進行傳輸命令和數(shù)據(jù)了

struct mmc_host_ops {         
    //用于SD卡命令的傳輸,比如發(fā)送和接收命令,CMD0,CMD8,ACMD41諸如此類的都是在這個函數(shù)去實現(xiàn)  
    void    (*request)(struct mmc_host *host, struct mmc_request *req);  
  
}  
  
static const struct mmc_host_ops msmsdcc_ops = {  
    .enable     = msmsdcc_enable,  
    .disable    = msmsdcc_disable,  
    .pre_req        = msmsdcc_pre_req,  
    .post_req       = msmsdcc_post_req,  
    .request    = msmsdcc_request,  
    .set_ios    = msmsdcc_set_ios,  
    .get_ro     = msmsdcc_get_ro,  
    .enable_sdio_irq = msmsdcc_enable_sdio_irq,  
    .start_signal_voltage_switch = msmsdcc_switch_io_voltage,  
    .execute_tuning = msmsdcc_execute_tuning,  
    .hw_reset = msmsdcc_hw_reset,  
    .stop_request = msmsdcc_stop_request,  
    .get_xfer_remain = msmsdcc_get_xfer_remain,  
    .notify_load = msmsdcc_notify_load,  
};  
  
/*這個函數(shù)實現(xiàn)了命令和數(shù)據(jù)的發(fā)送和接收, 
當(dāng) CORE 部分需要發(fā)送命令或者傳輸數(shù)據(jù)時,都會調(diào)用這個函數(shù),并傳遞 mrq 請求*/  
static void msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)  
    mmc_request_done(mmc, mrq);             // 如果卡不存在,就終止請求  
    msmsdcc_request_start(host, mrq);         
  
static void msmsdcc_request_start (struct msmsdcc_host *host, struct mmc_request *mrq)  
    if ((mrq->data->flags & MMC_DATA_READ) ||host->curr.use_wr_data_pend)      //判斷發(fā)送數(shù)據(jù)還是命令  
        msmsdcc_start_data(host, mrq->data,mrq->sbc ? mrq->sbc : mrq->cmd,0);   //發(fā)送數(shù)據(jù)  
    else  
        msmsdcc_start_command(host,mrq->sbc ? mrq->sbc : mrq->cmd,0);          //發(fā)送命令  
  
  
static void msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,struct mmc_command *cmd, u32 c)  
    //對某些 寄存器進行設(shè)置, 使能某些中斷, 如 pio_irqmask  
    ...  
    if (is_dma_mode(host) && (datactrl & MCI_DPSM_DMAENABLE))   //采用 DMA 進行數(shù)據(jù)傳輸還是采用 FIFO 進行數(shù)據(jù)傳輸  
        msmsdcc_start_command_deferred(host, cmd, &c);          //啟動了數(shù)據(jù)傳輸模式  
    else      
        msmsdcc_start_command(host, cmd, c)  
  
static void msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)  
{  
    msmsdcc_start_command_deferred(host, cmd, &c);  
    msmsdcc_start_command_exec(host, cmd->arg, c);  
}  
  
static void msmsdcc_start_command_deferred(struct msmsdcc_host *host,struct mmc_command *cmd, u32 *c)  
    cmd->opcode ----對應(yīng)SD卡命令 ,如 CMD0:復(fù)位SD 卡  

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多