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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

SD卡驱动分析(二)

發(fā)布時間:2025/4/16 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SD卡驱动分析(二) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

三.下面分析一下高通的android2.3的代碼中SD卡驅(qū)動的流程。

? ? ? ? ??在kernel中,SD卡是作為平臺設備加入到內(nèi)核中去的,在/kernel/arch/arm/mach-msm/devices-msm7627a.c中:

[cpp]?view plaincopy
  • static?void?__init?msm7x2x_init(void)??
  • ??->?static?void?__init?msm7x27a_init_mmc(void)??
  • ???????->?msm_add_sdcc(1,?&sdc1_plat_data);?//devices-msm7627a.c中,其中sdc1_plat_data結構體中定義了平臺相關的一些資源,比如檢測腳號等,當然我們這里沒有定義檢測腳號。??
  • ????????????->?pdev?=?msm_sdcc_devices[controller-1];??
  • ???????????pdev->dev.platform_data?=?plat;??
  • ???????????return?platform_device_register(pdev);??//在這里會向內(nèi)核的platform?bus總線上掛載SD卡的平臺設備??
  • ? ??

    ? ? ? ? ??同時KERNEL啟動的過程中在kernel/drivers/mmc/core/core.c文件內(nèi)會調(diào)用static int __init mmc_init(void)函數(shù):

    [cpp]?view plaincopy
  • static?int?__init?mmc_init(void)??
  • ??->?ret?=?mmc_register_bus();//向系統(tǒng)中注冊MMC?BUS??
  • ?????ret?=?mmc_register_host_class();//向系統(tǒng)中添加mmc_host這個class類??
  • ?????ret?=?sdio_register_bus();//向系統(tǒng)中注冊SDIO?BUS,我們所使用的SD卡沒有使用這個SDIO?BUS,至于原因我還不清楚,有待繼續(xù)學習。??
  • ? ??

    ? ??在/kernel/drivers/mmc/card/block.c中調(diào)用:

    [cpp]?view plaincopy
  • static?int?__init?mmc_blk_init(void)??
  • ??->res=register_blkdev(MMC_BLOCK_MAJOR,"mmc");???//申請塊設備號??
  • ????res?=?mmc_register_driver(&mmc_driver);?//向系統(tǒng)中注冊mmc_driver,會msm_sdcc.c中注冊的mmc_device相匹配后會調(diào)probe函數(shù)static?int?mmc_blk_probe(struct?mmc_card?*card)來申請一個塊設備文件,最終SD卡所有的驅(qū)動都是通過這個塊設備文件來調(diào)用的,也就是說,這個塊設備文件是KERNEL與上層的接口。??

  • ? ? 在kernel/drivers/mmc/host/msm_sdcc.c文件中調(diào)用static int__init msmsdcc_init(void),向內(nèi)核中注冊struct platform_driver msmsdcc_driver,這個platform_driver,與之前注冊的platform_devices相匹配后調(diào)用probe函數(shù):

    [cpp]?view plaincopy
  • static?int?msmsdcc_probe(struct?platform_device?*pdev)??
  • ??->?struct?mmc_platform_data?*plat?=?pdev->dev.platform_data??
  • ?????for?(i?=?0;?i?<?pdev->num_resources;?i++)?//獲取平臺相關信息??
  • ?????mmc=mmc_alloc_host(sizeof(struct?msmsdcc_host),?&pdev->dev);?//分配mmc_host結構體,同時嵌入msmsdcc_host結構體,這樣方便以后由這兩個結構體互相找到對方。mmc_host這個結構體是串聯(lián)整個SD卡驅(qū)動的核心,需要特別注意。同時mmc_alloc_host這個函數(shù)很重要,稍后再來分析。??
  • ?????host?=?mmc_priv(mmc);??
  • ?????host->mmc?=?mmc;??//這里就是在兩個結構體中相互轉換????????????????????????????????????????????????????????????<p>?????/*??…….??*/????中間這段代碼主要是從內(nèi)核空間到用戶空間的映射,以及設置一些時鐘</p><p>?????mmc->ops?=&msmsdcc_ops;?//設置mmc_host的操作函數(shù)</p><p>?????mmc->caps|=?plat->mmc_bus_width;</p><p>?????ret?=request_irq(core_irqres->start,?msmsdcc_irq,?IRQF_SHARED,?DRIVER_NAME?"(cmd)",?host);?//申請中斷,我們由于沒有使用中斷腳,所以這里不會調(diào)用</p><p>?????mmc_add_host(mmc);//向系統(tǒng)中添加mmc_host設備,稍后再分析這個函數(shù)</p>??

  • ? ? 然后我們來分析剛才提到的mmc_alloc_host函數(shù):

    [cpp]?view plaincopy
  • <p>struct?mmc_host?*mmc_alloc_host(int?extra,?structdevice?*dev)</p><p>?->?struct?mmc_host*host;</p><p>????host?=kzalloc(sizeof(struct?mmc_host)?+?extra,?GFP_KERNEL);//這里要注意,我們觀察mmc_host結構體會發(fā)現(xiàn)結構體的最后一個成員unsigned?long?private[0]?____cacheline_aligned?沒有實際意思,僅表示一個地址,而我們正是利用這一點,將mmc_host結構體與上面?zhèn)鬟M來的msmsdcc_host結構體聯(lián)系起來的。</p><p>????dev_set_name(&host->class_dev,"mmc%d",?host->index);</p><p>????host->parent=?dev;</p><p>????host->class_dev.parent=?dev;</p><p>????host->class_dev.class=?&mmc_host_class;?<span?style="font-family:?KaiTi_GB2312;?">//這一段會在sys/class/mmc_host/下建立mmc%d的一個文件</span></p><p>????INIT_DELAYED_WORK(&host->detect,mmc_rescan);//初始化一個工作隊列,延時函數(shù)為mmc_rescan,這個函數(shù)非常重要,后面再分析。</p><p>????host->max_segs=?1;</p><p>????host->max_seg_size=?PAGE_CACHE_SIZE;?<span?style="font-family:?KaiTi_GB2312;?">//后面這些代碼是對host進行一個默認的設置,有些設置可能會被上文中的probe函數(shù)替換掉</span></p>??
  • ? ?

    ? ?還記得之前在msm_sdcc.c中的msmsdcc_probe函數(shù)快結束的時候有mmc_add_host(mmc)這樣一個函數(shù)嗎?下面我們就來分析這個函數(shù):

    [cpp]?view plaincopy
  • int?mmc_add_host(struct?mmc_host?*host)??
  • ?->?err?=?device_add(&host->class_dev);??
  • ?????->?dev_set_name(dev,?"%s",?dev->init_name);??
  • ????????error?=?device_create_file(dev,?&uevent_attr);??
  • ????????error?=?bus_add_device(dev);??
  • ????????//是不是有一種很親切的感覺呢,對了,這里就是在添加一個mmc_host的devices,會與block.c中注冊的mmc_driver相匹配??
  • ????mmc_start_host(host);??
  • ?????->?mmc_power_off(host);??
  • ?????????->?mmc_set_ios(host);??
  • ?????????????->?host->ops->set_ios(host,?ios);//看到了嗎,調(diào)用的是msm_sdcc.c中設置的struct?mmc_host_ops?msmsdcc_ops中的set_ios設置寄存器??
  • ????mmc_detect_change(host,?0);??
  • ??????->?mmc_schedule_delayed_work(&host->detect,?delay);?//這里調(diào)用host的工作隊列,而這里delay就是上面添加的mmc_rescan函數(shù),即調(diào)用此函數(shù)??

  • ? ? 好了,剛才說了很多的mmc_rescan函數(shù)也等不及了,快來一睹它的真容吧:

    [cpp]?view plaincopy
  • void?mmc_rescan(struct?work_struct?*work)??
  • ??->?struct?mmc_host?*host?=?container_of(work,?struct?mmc_host,?detect.work);//這個函數(shù)在LINUX里經(jīng)常會用到,是內(nèi)核黑客為了方便我們由一個結構體里一個成員的指針來得到整個結構體的指針所寫的一個函數(shù),非常有用??
  • ?????if?(host->bus_ops?&&?host->bus_ops->detect?&&?!host->bus_dead?&&?!(host->caps?&?MMC_CAP_NONREMOVABLE))?//這段是在系統(tǒng)喚醒的時候(由于在開機時已經(jīng)設置了bus_ops)才會調(diào)用,所以KERNEL剛起的時候不會調(diào)用??
  • ?????mmc_rescan_try_freq(host,?host->f_min)??
  • ??????->?mmc_power_up(host);//與上文分析的power_down類似??
  • ?????????sdio_reset(host)//好像是讓SDIO總線回到初始狀態(tài),我不是太清楚??
  • ?????????mmc_go_idle(host)??
  • ??????????->?cmd.opcode?=?MMC_GO_IDLE_STATE//即發(fā)送CMD0使SD卡處于IDLE狀態(tài)??
  • ?????????mmc_send_if_cond(host,?host->ocr_avail)??
  • ??????????->?cmd.opcode?=?SD_SEND_IF_COND//這個命令是專門為SD2.0協(xié)議的設備初始化使用的,只有SD2.0才支持這個命令??
  • ?????????if?(!mmc_attach_sdio(host))??
  • ?????????if?(!mmc_attach_sd(host))??
  • ?????????if?(!mmc_attach_mmc(host))?//這里依次判斷外設是SDIO卡,SD卡或MMC卡中的哪一種,由于三種設備的協(xié)議會有一些差別,所以判斷出來是哪一種設備后才好調(diào)用相應的操作函數(shù)??

  • ? ? 下面以mmc_attach_sd為例來分析:

    [cpp]?view plaincopy
  • int?mmc_attach_sd(struct?mmc_host?*host)??
  • ??->?err?=?mmc_send_app_op_cond(host,?0,?&ocr)??//發(fā)送CMD41來獲取SD卡所支持的電壓范圍??
  • ?????mmc_sd_attach_bus_ops(host)???
  • ??????->?bus_ops?=?&mmc_sd_ops?//設置host->bus_ops??
  • ?????mmc_sd_init_card(host,?host->ocr,?NULL)??
  • ???????->?err?=?mmc_sd_get_cid(host,?ocr,?cid,?&rocr)??
  • ???????????->?err?=?mmc_all_send_cid(host,?cid)?//發(fā)送CMD2以獲取卡的身份信息??
  • ??????????card?=?mmc_alloc_card(host,?&sd_type)?//分配一張SD結構的card??
  • ??????????mmc_send_relative_addr(host,?&card->rca)//獲取卡的相對地址??
  • ??????????err?=?mmc_sd_get_csd(host,?card)?//獲取卡的寄存器的信息,包括?block?長度,卡容量等信息??
  • ??????????err?=?mmc_select_card(card)?//發(fā)送?CMD7,?選中目前?RADD?地址上的卡,任何時候總線上只有一張卡被選中,進入了傳輸狀態(tài)??
  • ??????????err?=?mmc_sd_setup_card(host,?card,?oldcard?!=?NULL)???
  • ???????????->?err?=?mmc_app_send_scr(card,?card->raw_scr)??
  • ??????????????if?(host->ops->get_ro)?//判斷是否有寫保護,若有設置為只讀卡??
  • ??????????err?=?mmc_app_set_bus_width(card,?MMC_BUS_WIDTH_4)?//設置傳輸模式的總線寬度??

  • ? ? 到此為止,就完成了整個SD卡起動初始化的過程,在啟動初始化完成之后,以后系統(tǒng)要調(diào)用SD卡的相動,都會通過之前注冊的塊設備來一步步的向下調(diào)用。

    總結

    以上是生活随笔為你收集整理的SD卡驱动分析(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。