日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

sd 卡驱动--基于高通平台

發(fā)布時間:2025/4/16 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sd 卡驱动--基于高通平台 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊打開鏈接

內容來自以下博客:

http://blog.csdn.net/qianjin0703/article/details/5918041 Linux設備驅動子系統(tǒng)第二彈 - SD卡 (有介紹SD卡硬件)
http://blog.csdn.net/wavemcu/article/details/7366852???? linux2.6內核SD Card Driver詳細解析之一
http://blog.chinaunix.net/uid-147915-id-3063162.html ?? ? 基于S3C2410的SD卡linux驅動工作原理
http://www.cnblogs.com/autum/archive/2012/08/16/SD.html? SD卡驅動分析(一)(系列關于 SD 卡文章)
http://blog.163.com/fenglang_2006/blog/static/133662318201011183912576/ linux sd卡驅動分析,基于mini2440,sdio mmc sd卡驅動編4


一、先來一些簡單硬件知識:

MMC:MMC就是 MultiMediaCard 的縮寫,即多媒體卡
SD:SD卡為Secure Digital Memory Card, 即安全數碼卡,(另TF卡又稱microSD)
SDIO:SDIO是在SD標準上定義了一種外設接口
MCI:MCI是Multimedia Card Interface的簡稱,即多媒體卡接口。上述的MMC,SD,SDI卡定義的接口都屬于MCI接口

SD卡引腳:

一根指令線CMD,4根數據線DAT0~DAT3,一個 SDCARD_DET_N 檢測引腳


SD卡內部有7個寄存器
OCR,CID,CSD和SCR寄存器保存卡的配置信息
RCA寄存器保存著通信過程中卡當前暫時分配的地址(只適合SD模式)
卡狀態(tài)(Card Status)和SD狀態(tài)(SD Status)寄存器保存著卡的狀態(tài)


OCR寄存器保存著SD/MMC卡的供電電允許范圍
CID為一個16個字節(jié)的寄存器,該寄存器包含一個獨特的卡標識號
CSD寄存器(卡特殊數據寄存器)包含訪問卡存儲時需要的相關信息


SD卡命令共分為12類,分別為class0到Class11
CMD0:復位SD 卡
CMD1:讀OCR寄存器
...

二、好,開始軟件部分了。

Linux相關MMC的代碼分布,主要有兩個目錄,一個頭文件目錄和一個源代碼目錄
頭文件目錄:include/linux/mmc
源代碼目錄:drivers/mmc

mmc驅動共分為三個目錄:card/、core/、host/
card:塊設備的驅動程序。這部分就是實現了將SD卡如何實現為塊設備的
core:總線驅動程序。這是整個MMC的核心層,這部分完成了不同協(xié)議和規(guī)范的實現,并且為HOST層的驅動提供接口函數
host:通訊接口驅動。針對不同主機的驅動程序,這一部分需要根據自己的特定平臺來完成

MMC/SD卡的驅動被分為:卡識別階段和數據傳輸階段
卡識別階段:空閑(idle)、準備(ready)、識別(ident)、等待(stby)、不活動(ina)
數據傳輸階段:發(fā)送(data)、傳輸(tran)、接收(rcv)、程序(prg)、斷開連接(dis)

在實際驅動開發(fā)中,只需要在host文件夾下實現你具體的MMC/SD設備驅動部分代碼,
也就是控制器(支持對MMC/SD卡的控制,俗稱MMC/SD主機控制器)和SDI控制器與MMC/SD卡的硬件接口電路


其實SD驅動一共就做了兩件事件:
1).卡的檢測。(初始化sd卡)
2).卡數據的讀取:
寫sd卡:POLL、中斷、DMA
讀sd卡:POLL、中斷、DMA


可以從以下幾個方面理解驅動:
1、 msm_sdcc.c代碼初始化過程;
2、 SD卡塊設備注冊過程;
3、 request及數據傳輸的實現


SD 傳輸模式有以下 3 種:
?? ?SPI mode (required )
?? ?1-bit mode
?? ?4-bit mode


開始上代碼

三、重要的結構體

[cpp]?view plaincopy
  • 卡控制器??
  • kernel/include/linux/mmc/host.h??
  • struct?mmc_host?{??
  • ????const?struct?mmc_host_ops?*ops;?????//?SD卡主控制器的操作函數,即該控制器所具備的驅動能力??
  • ????struct?mmc_ios??????ios;????????????//?配置時鐘、總線、電源、片選、時序等??
  • ????truct?mmc_card??????*card;??????????//?連接到此主控制器的SD卡設備??
  • ????const?struct?mmc_bus_ops?*bus_ops;??//?SD總線驅動的操作函數,即SD總線所具備的驅動能力??
  • ????...??
  • ??????
  • }??
  • ??
  • 卡控制器操作集??
  • 用于從主機控制器向?core?層注冊操作函數,從而將core層與具體的主機控制器隔離??
  • 也就是說?core?要操作主機控制器,就是這個?ops?當中給的函數指針操作,不能直接調用具體主控制器的函數??
  • struct?mmc_host_ops?{???-----------------非常重要??
  • ??????
  • ????int?(*enable)(struct?mmc_host?*host);???//使能和禁止HOST控制器??
  • ????int?(*disable)(struct?mmc_host?*host);??
  • ??????
  • ????void????(*request)(struct?mmc_host?*host,?struct?mmc_request?*req);?//核心函數,用于SD卡命令的傳輸,比如發(fā)送和接收命令,CMD0,CMD8,ACMD41諸如此類的都是在這個函數去實現???
  • ??????
  • ????void????(*set_ios)(struct?mmc_host?*host,?struct?mmc_ios?*ios);?//配置時鐘、總線、電源、片選、時序等???
  • ????int?(*get_ro)(struct?mmc_host?*host);???//用于檢測SD卡的寫保護是否打開?????
  • ????int?(*get_cd)(struct?mmc_host?*host);???//用于SD卡的檢測,是否有卡插入和彈出??
  • ????void????(*enable_sdio_irq)(struct?mmc_host?*host,?int?enable);??//開啟sdio中斷??
  • ????...??
  • }??
  • ??
  • 控制器對卡的I/O狀態(tài)??
  • struct?mmc_ios?{??
  • ??????
  • }??
  • ??
  • 描述卡??
  • kernel/include/linux/mmc/card.h??
  • struct?mmc_card?{??
  • ??????
  • }??
  • ??
  • 讀寫MMC卡的請求??
  • 包括命令,數據以及請求完成后的回調函數??
  • struct?mmc_request?{??
  • ????struct?mmc_command??*sbc;???????/*?SET_BLOCK_COUNT?for?multiblock?*/??
  • ????struct?mmc_command??*cmd;??
  • ????struct?mmc_data?????*data;??
  • ????struct?mmc_command??*stop;??
  • ??
  • ????struct?completion???completion;??
  • ????void??(*done)(struct?mmc_request?*);/*?completion?function?*/??
  • ????struct?mmc_host?????*host;??
  • };??
  • ??
  • MMC卡讀寫的數據相關信息??
  • 如:請求,操作命令,數據以及狀態(tài)等??
  • struct?mmc_data?{??
  • ??????
  • }??
  • ??
  • MMC卡操作相關命令及數據,狀態(tài)信息等??
  • 一條指令command共48位,其中command?index指代這條具體的指令名稱,argument為該指令的參數??
  • struct?mmc_command?{??
  • ????u32?????????opcode;?????//對應command?index??
  • ????u32?????????arg;????????//?對應argument??
  • ????u32?????????resp[4];????//?對應response??
  • ????...??
  • }??
  • ??
  • 描述mmc卡驅動??
  • struct?mmc_driver?{??
  • ????struct?device_driver?drv;??
  • ????int?(*probe)(struct?mmc_card?*);??
  • ????void?(*remove)(struct?mmc_card?*);??
  • ????int?(*suspend)(struct?mmc_card?*);??
  • ????int?(*resume)(struct?mmc_card?*);??
  • ????void?(*shutdown)(struct?mmc_card?*);??
  • };??
  • ??
  • 總線操作結構??
  • 由于mmc卡支持多種總數據線,如SPI、SDIO、8LineMMC,而不同的總線的操作控制方式不盡相同,所以通過此結構與相應的總線回調函數相關聯??
  • struct?mmc_bus_ops?{??
  • ????void?(*remove)(struct?mmc_host?*);??//拔出SD卡的回調函數??
  • ????void?(*detect)(struct?mmc_host?*);??//探測SD卡是否還在SD總線上的回調函數,具體實現是發(fā)送CMD13命令,并讀回響應,如果響應錯誤,則依次調用.remove、detach_bus來移除卡及釋放總線??
  • ????...??
  • };??

  • 四、涉及到三種總線

    [cpp]?view plaincopy
  • 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)建的.通過調用?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)建的.通過調用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,??
  • };??
  • 對于 platform bus 上的設備,通常初始化的流程是:
    a. 在 platform bus上注冊 platform device.
    b. 在 platform bus上注冊 platform driver.
    c. 如果 platform bus 上的 device 和 driver 相互匹配, 則調用其 probe() 函數進行初始化.

    對于SD host controller 設備也是一樣.

    [cpp]?view plaincopy
  • 1.?注冊?platform?device??
  • board-9625.c?(arch\arm\mach-msm)??
  • void?__init?msm9625_init(void)??
  • ????board_dt_populate(msm9625_auxdata_lookup)??
  • ????????of_platform_populate(of_find_node_by_path("/soc"),of_default_bus_match_table,?adata,?NULL);??
  • ??????????
  • kernel\arch\arm\boot\dts\msm9625.dtsi??
  • ????sdcc2:?qcom,sdcc@f98a4000?{??
  • ????????cell-index?=?<2>;?/*?SDC2?SD?card?slot?*/??
  • ????????compatible?=?"qcom,msm-sdcc";??
  • ????????...??
  • ????}??
  • ??
  • ??
  • 2.?注冊?platform?driver:??
  • driver/mmc/host/msm_sdcc.c??
  • static?int?__init?msmsdcc_init(void)??
  • ????platform_driver_register(&msmsdcc_driver);??

  • 五、總體架構及流程

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

    [cpp]?view plaincopy
  • 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");//注冊一個塊設備??
  • ????res?=?mmc_register_driver(&mmc_driver);//注冊一個mmc設備驅動??
  • ??
  • 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主機實例,塊設備中的讀寫操作就是調用這個mmc主機的操作函數host->ops->request來實現對實際硬件的操作。??

  • 然后再掛載 mmc 設備驅動,執(zhí)行驅動程序中的xx_mmc_probe(),檢測host設備中掛載的sd設備。

    [cpp]?view plaincopy
  • 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"的設備,如果有,?驅動程序將主控制器掛載到?platform?總線上,并注冊該驅動程序??
  • 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,??
  • ????},??
  • };??????
  • ??????
  • //整個設備驅動的?probe()函數,其本質就是是為設備建立起數據結構并對其賦初值??
  • //msmsdcc_probe?所有賦值中,我們重點關注從?platform_device?*pdev里得到的數據,即設備樹里的數據??
  • //platform_device?*pdev是在系統(tǒng)初始化的時候掃描?platform?總線發(fā)現SD主控制器后所得到的數據??
  • static?int?msmsdcc_probe(struct?platform_device?*pdev)??????
  • {??????
  • ????//初始化設備的數據結構??
  • ????if?(pdev->dev.of_node)?{??
  • ????plat?=?msmsdcc_populate_pdata(&pdev->dev);????????//獲取設備樹信息??
  • ????of_property_read_u32((&pdev->dev)->of_node,"cell-index",?&pdev->id);??
  • ????}?else?{??
  • ????????plat?=?pdev->dev.platform_data;??
  • ????}??
  • ????//為主設備控制器建立數據結構,建立kobject,并初始化等待隊列,工作隊列,以及一些控制器的配置??
  • ????mmc?=?mmc_alloc_host(sizeof(struct?msmsdcc_host),?&pdev->dev);????????????----?1??
  • ????//實現設備驅動的功能函數,如mmc->ops?=?&pxamci_ops;??
  • ????mmc->ops?=?&msmsdcc_ops;??
  • ????//申請中斷函數?request_irq()??
  • ????ret?=?request_irq(core_irqres->start,?msmsdcc_irq,?IRQF_SHARED,DRIVER_NAME?"?(cmd)",?host);??
  • ????//注冊設備,即注冊kobject,建立sys文件,發(fā)送uevent等??
  • ????mmc_add_host(mmc);????????????????????????????????????????????????????????----?2??
  • ????//其他需求,如在/proc/driver下建立用戶交互文件等??
  • ????ret?=?device_create_file(&pdev->dev,?&host->auto_cmd21_attr);??
  • }??????
  • 此時probe函數會創(chuàng)建一個host設備,然后開啟一個延時任務 mmc_rescan()

    [cpp]?view plaincopy
  • 1:????
  • core/host.c???
  • //重要函數mmc_alloc_host?,?用于分配mmc_host結構體指針的內存空間大小??
  • struct?mmc_host?*mmc_alloc_host(int?extra,?struct?device?*dev)----創(chuàng)建一個?mmc_host?和?mmc_spi_host?,且mmc_host的最后一個成員指針private指向mmc_spi_host??
  • ????//建立數據結構??
  • ????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);????//建立了一個工作隊列任務?structdelayed_work?detect。工作隊列任務執(zhí)行的函數為mmc_rescan??
  • ????//配置控制器??
  • ????host->max_segs?=?1;??
  • ????host->max_seg_size?=?PAGE_CACHE_SIZE;??
  • ????return?host;??

  • 驅動掛載成功后, mmc_rescan()函數被執(zhí)行,然后對卡進行初始化

    [cpp]?view plaincopy
  • core/core.c??
  • //mmc_rescan?函數是需要重點關注的,因為SD卡協(xié)議中的檢測,以及卡識別等都是在此函數中實現??
  • void?mmc_rescan(struct?work_struct?*work)??
  • ????if?(host->bus_ops?&&?host->bus_ops->detect?&&?!host->bus_dead?&&?!(host->caps?&?MMC_CAP_NONREMOVABLE))????//存在熱插拔卡,不包括emmc,調用探測函數??
  • ????host->bus_ops->detect(host);??
  • ????mmc_bus_put(host);????//減少引用技術,就釋放??
  • ????mmc_bus_get(host);????//增加bus引用計數??
  • ????if?(host->bus_ops?!=?NULL)?{??
  • ????????mmc_bus_put(host);????//如果卡仍然存在,減少引用計數,不必探測了??
  • ????????goto?out;??
  • ????}??
  • ????if?(host->ops->get_cd?&&?host->ops->get_cd(host)?==?0)??//有卡,退出??
  • ????goto?out;??
  • ????mmc_claim_host(host);???????????????????//用于檢測host是否被占用,占用則退出,否則標記成占用??
  • ??????
  • ????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,如響應為無效命令,則卡為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類型的判斷依據。
    f、如果ACMD41和CMD1都不能通過,那這張卡恐怕就是無效卡了,初始化失敗。
    [cpp]?view plaincopy
  • static?int?mmc_rescan_try_freq(struct?mmc_host?*host,?unsigned?freq)??
  • ????host->f_init?=?freq;?????????????????//設置某一個時鐘頻率??
  • ????mmc_power_up(host);?????????????????????//與?mmc_power_off?類似,不過設置了啟動時需要的?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;????????????????????//此命令無參數??
  • ????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));??//調用了?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)???----重要函數??
  • ????__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);???????????????//設置MMC電壓??
  • ????err?=?mmc_init_card(host,?host->ocr,?NULL);??????????????//對mmc卡進行初始化,主要是讀取mmc卡里的一些寄存器信息,且對這些寄存器的值進行設置??
  • ????err?=?mmc_sd_init_card(host,?host->ocr,?NULL);???----1b2??
  • ????err?=?mmc_add_card(host->card);??????????????????----1b3?//調用?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?結構??
  • ????err?=?mmc_send_relative_addr(host,?&card->rca);??????//獲取卡的相對地址,注意一前卡和主機通信都采用默認地址,現在有了自己的地址了,進入到?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?寄存器的內容,進入到?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)設置為只讀狀態(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?設備?mmc_card?了??????
  • ??????
  • ??????
  • ***********???
  • 2:??
  • //完成kobject的注冊,并調用?mmc_rescan,目的在于在系統(tǒng)初始化的時候就掃描SD總線查看是否存在SD卡??
  • int?mmc_add_host(struct?mmc_host?*host)??
  • ????err?=?device_add(&host->class_dev);//將設備注冊進linux設備模型,最終的結果就是在?sys/bus/platform/devices?目錄下能見到?mmc?設備節(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?進行了設置??
  • ????...??
  • ????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);?//實際上就是調用我們前面說的延時函數?mmc_rescan??

  • 關于命令和數據的發(fā)送和接收

    [cpp]?view plaincopy
  • struct?mmc_host_ops?{?????????
  • ????//用于SD卡命令的傳輸,比如發(fā)送和接收命令,CMD0,CMD8,ACMD41諸如此類的都是在這個函數去實現??
  • ????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,??
  • };??
  • ??
  • /*這個函數實現了命令和數據的發(fā)送和接收,?
  • 當?CORE?部分需要發(fā)送命令或者傳輸數據時,都會調用這個函數,并傳遞?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ā)送數據還是命令??
  • ????????msmsdcc_start_data(host,?mrq->data,mrq->sbc???mrq->sbc?:?mrq->cmd,0);???//發(fā)送數據??
  • ????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)??
  • ????//對某些?寄存器進行設置,?使能某些中斷,?如?pio_irqmask??
  • ????...??
  • ????if?(is_dma_mode(host)?&&?(datactrl?&?MCI_DPSM_DMAENABLE))???//采用?DMA?進行數據傳輸還是采用?FIFO?進行數據傳輸??
  • ????????msmsdcc_start_command_deferred(host,?cmd,?&c);??????????//啟動了數據傳輸模式??
  • ????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?----對應SD卡命令?,如?CMD0:復位SD?卡??

  • 六、SD卡熱插拔檢測的兩種方法

    1.中斷

    在probe 中有三個中斷函數:

    [cpp]?view plaincopy
  • ret?=?request_irq(core_irqres->start,?msmsdcc_irq,?IRQF_SHARED,?DRIVER_NAME?"?(cmd)",?host);????//命令中斷??
  • ret?=?request_irq(core_irqres->start,?msmsdcc_pio_irq,?IRQF_SHARED,?DRIVER_NAME?"?(pio)",?host);//IO中斷????????????
  • ret?=?request_irq(plat->sdiowakeup_irq,msmsdcc_platform_sdiowakeup_irq,IRQF_SHARED?|?IRQF_TRIGGER_LOW,?DRIVER_NAME?"sdiowakeup",?host);???
  • [cpp]?view plaincopy
  • //真正的?SD?卡檢測中斷:???
  • ????ret?=?request_threaded_irq(plat->status_irq,?NULL,msmsdcc_platform_status_irq,?plat->irq_flags,?DRIVER_NAME?"?(slot)",?host);??
  • ??
  • //在?msmsdcc_probe?中調用?msmsdcc_populate_pdata?獲取設備樹信息:??
  • static?struct?mmc_platform_data?*msmsdcc_populate_pdata(struct?device?*dev)??
  • ????msmsdcc_dt_parse_gpio_info(dev,?pdata)??????//獲取設備樹種?GPIO?信息??
  • ??
  • static?int?msmsdcc_dt_parse_gpio_info(struct?device?*dev,?struct?mmc_platform_data?*pdata)??
  • ????msmsdcc_dt_get_cd_wp_gpio(dev,?pdata);??
  • ??
  • static?void?msmsdcc_dt_get_cd_wp_gpio(struct?device?*dev,?struct?mmc_platform_data?*pdata)??
  • ????pdata->status_gpio?=?of_get_named_gpio_flags(np,"cd-gpios",?0,?&flags);??//獲取中斷的?gpio??
  • ????pdata->status_irq?=?platform_get_irq_byname(pdev,?"status_irq");?//獲取?status_irq?的中斷名??
  • ??
  • //設備樹里關于中斷的信息:??
  • apps_proc\kernel\arch\arm\boot\dts\msm9625.dtsi??
  • ????interrupt-names?=?"core_irq",?"bam_irq",?"status_irq";??
  • ????cd-gpios?=?<&msmgpio?66?0>;??
  • ??????
  • static?irqreturn_t?msmsdcc_platform_status_irq(int?irq,?void?*dev_id)??
  • ????msmsdcc_check_status((unsigned?long)?host);??
  • ??
  • static?void?msmsdcc_check_status(unsigned?long?data)??
  • ????if?(host->plat->status?||?gpio_is_valid(host->plat->status_gpio))???//檢測?GPIO?的狀態(tài)??
  • ????mmc_detect_change(host->mmc,?0);??
  • ??
  • void?mmc_detect_change(struct?mmc_host?*host,?unsigned?long?delay)??
  • ????mmc_schedule_delayed_work(&host->detect,?delay);??
  • 2.輪詢:

    [cpp]?view plaincopy
  • Msm_sdcc.c?(drivers\mmc\host)??
  • static?int?msmsdcc_probe(struct?platform_device?*pdev)??
  • ????mmc->caps?|=?MMC_CAP_NEEDS_POLL;?????????????//設置輪詢標志??
  • ??????
  • core/core.c??
  • void?mmc_rescan(struct?work_struct?*work)??
  • ????out:??
  • ????????if?(host->caps?&?MMC_CAP_NEEDS_POLL)???????????
  • ????????mmc_schedule_delayed_work(&host->detect,?HZ);//輪詢??

  • 以上僅是SD卡驅動部分信息,其他關于塊設備,總線知識,linux驅動中已經很成熟了,暫時也就沒有了解。

    ?七、開始上圖片了

    初始化:


    卡識別:

    數據傳輸:


    request


    總結

    以上是生活随笔為你收集整理的sd 卡驱动--基于高通平台的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: av在线观看地址 | 久久久久久久国产精品毛片 | 久久99这里只有精品 | 一区二区不卡视频 | 精品人妻伦一二三区久 | youjizz少妇| 久久精品国产亚洲av高清色欲 | 成人性生交大片免费看96 | 国产视频三级 | 欧美午夜激情视频 | 国产无人区码熟妇毛片多 | 成人午夜性视频 | 桃色av网站 | 丰满尤物白嫩啪啪少妇 | 中文字幕视频一区 | 午夜精品久久久久久久久久久久久蜜桃 | 96超碰在线 | 好男人天堂网 | 777精品| 亚洲av无码乱码国产麻豆 | 天天精品视频 | 特大黑人巨交性xxxx | 毛茸茸free性熟hd | 日韩少妇毛片 | 黄色网页在线 | 四色成人av永久网址 | 国产尤物| 伊人三区| 天天槽| 毛片美女 | 国产传媒一区 | 欧美色综合网站 | 五月婷视频 | 91精品国产色综合久久不卡98口 | 免费av的网站 | 综合久久91 | 国产麻豆一区二区三区 | 黄色网址在线免费看 | 三级黄片毛片 | 高清av网 | 亚洲av无码国产精品久久久久 | 亚洲欧洲成人在线 | 91久色视频 | 免费无码国产精品 | 色开心| 四虎国产视频 | 国产伦精品一区二区三区免.费 | 秋霞电影一区二区 | 国产麻豆乱码精品一区二区三区 | 毛片内射久久久一区 | 亚洲天堂岛 | 五月婷婷六月综合 | 国产成年人免费视频 | 对白刺激国产子与伦 | 成人乱人乱一区二区三区 | 亚洲人成电影网站 | 精品人妻aV中文字幕乱码色欲 | 黄页嫩草 | 免费在线黄色网 | 日韩图色 | 色久av | www.com国产 | 波多野结衣一本一道 | 理想之城连续剧40集免费播放 | 视频在线观看一区 | 欧美日韩免费做爰视频 | 国产第100页 | 女女同性被吸乳羞羞 | 国产a级片视频 | 精品九九九九九 | 欧美 日韩 视频 | 波多野结衣在线 | 91大神网址| 久久精品欧美 | 天天射天天干天天操 | 国产视频一二 | 欧美入口| 久久aⅴ乱码一区二区三区 亚洲成人18 | 国产精品卡一卡二 | 日日夜夜综合网 | 国产一区二区三区黄片 | 久久精品999 | 日本国产高清 | 日本黄色片段 | 欧美放荡性医生videos | 日本午夜精华 | 在线看片黄 | 91丨porny丨在线中文 | 免费三级av | 成人免费看片在线观看 | 午夜视频在线观看一区二区 | 亚洲人成人无码网www国产 | 视频福利在线观看 | 在线国产一区二区三区 | 亚洲乱熟女一区二区 | 欧美精品日韩在线 | 在线黄网 | 亚洲精品中文字幕在线观看 | 伊人影音|