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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析

發(fā)布時間:2023/12/9 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

SDIO-Wifi模塊是基于SDIO接口的符合wifi無線網(wǎng)絡標準的嵌入式模塊,內(nèi)置無線網(wǎng)絡協(xié)議IEEE802.11協(xié)議棧以及TCP/IP協(xié)議棧,能夠?qū)崿F(xiàn)用戶主平臺數(shù)據(jù)通過SDIO口到無線網(wǎng)絡之間的轉(zhuǎn)換。SDIO具有傳輸數(shù)據(jù)快,兼容SD、MMC接口等特點。

? ? ?對于SDIO接口的wifi,首先,它是一個sdio的卡的設備,然后具備了wifi的功能,所以,注冊的時候還是先以sdio的卡的設備去注冊的。然后檢測到卡之后就要驅(qū)動他的wifi功能了,顯然,他是用sdio的協(xié)議,通過發(fā)命令和數(shù)據(jù)來控制的。下面先簡單回顧一下SDIO的相關知識:

一、SDIO相關基礎知識解析

1、SDIO接口

? ? ???SDIO?故名思義,就是?SD 的 I/O 接口(interface)的意思,不過這樣解釋可能還有點抽像。更具體的說明,SD 本來是記憶卡的標準,但是現(xiàn)在也可以把 SD 拿來插上一些外圍接口使用,這樣的技術便是 SDIO。

? ? ? ?所以 SDIO 本身是一種相當單純的技術,透過 SD 的 I/O 接腳來連接外部外圍,并且透過 SD 上的 I/O 數(shù)據(jù)接位與這些外圍傳輸數(shù)據(jù),而且 SD 協(xié)會會員也推出很完整的 SDIO stack 驅(qū)動程序,使得 SDIO 外圍(我們稱為SDIO 卡)的開發(fā)與應用變得相當熱門。

? ? ? ?現(xiàn)在已經(jīng)有非常多的手機或是手持裝置都支持 SDIO 的功能(SD 標準原本就是針對 mobile device 而制定),而且許多 SDIO 外圍也都被開發(fā)出來,讓手機外接外圍更加容易,并且開發(fā)上更有彈性(不需要內(nèi)建外圍)。目前常見的 SDIO 外圍(SDIO 卡)有:

· Wi-Fi card(無線網(wǎng)絡卡)?

· CMOS sensor card(照相模塊)?

· GPS card?

· GSM/GPRS modem card?

· Bluetooth card?

? ? ? ? SDIO 的應用將是未來嵌入式系統(tǒng)最重要的接口技術之一,并且也會取代目前 GPIO 式的 SPI 接口。


2、SDIO總線

? ? ? SDIO總線 和 USB總線 類似,SDIO也有兩端,其中一端是HOST端,另一端是device端。所有的通信都是由HOST端 發(fā)送 命令 開始的,Device端只要能解析命令,就可以相互通信

CLK信號:HOST給DEVICE的 時鐘信號,每個時鐘周期傳輸一個命令。

CMD信號:雙向 的信號,用于傳送 命令 和 反應。

DAT0-DAT3 信號:四條用于傳送的數(shù)據(jù)線。

VDD信號:電源信號。

VSS1,VSS2:電源地信號。


3、SDIO熱插拔原理

方法:設置一個?定時器檢查?或?插拔中斷檢測

硬件:假如GPG10(EINT18)用于SD卡檢測

GPG10 為高電平 即沒有插入SD卡

GPG10為低電平 ?即插入了SD卡


4、SDIO命令

? ? ? SDIO總線上都是HOST端發(fā)起請求,然后DEVICE端回應請求。sdio命令由6個字節(jié)組成。

a -- Command:用于開始傳輸?shù)拿?#xff0c;是由HOST端發(fā)往DEVICE端的。其中命令是通過CMD信號線傳送的。

b -- Response:回應是DEVICE返回的HOST的命令,作為Command的回應。也是通過CMD線傳送的。

c -- Data:數(shù)據(jù)是雙向的傳送的。可以設置為1線模式,也可以設置為4線模式。數(shù)據(jù)是通過DAT0-DAT3信號線傳輸?shù)摹?/p>

? ? ? SDIO的每次操作都是由HOST在CMD線上發(fā)起一個CMD,對于有的CMD,DEVICE需要返回Response,有的則不需要。

? ? ?對于讀命令,首先HOST會向DEVICE發(fā)送命令,緊接著DEVICE會返回一個握手信號,此時,當HOST收到回應的握手信號后,會將數(shù)據(jù)放在4位的數(shù)據(jù)線上,在傳送數(shù)據(jù)的同時會跟隨著CRC校驗碼。當整個讀傳送完畢后,HOST會再次發(fā)送一個命令,通知DEVICE操作完畢,DEVICE同時會返回一個響應。

? ? 對于寫命令,首先HOST會向DEVICE發(fā)送命令,緊接著DEVICE會返回一個握手信號,此時,當HOST收到回應的握手信號后,會將數(shù)據(jù)放在4位的數(shù)據(jù)線上,在傳送數(shù)據(jù)的同時會跟隨著CRC校驗碼。當整個寫傳送完畢后,HOST會再次發(fā)送一個命令,通知DEVICE操作完畢,DEVICE同時會返回一個響應。


二、SDIO接口驅(qū)動

? ? ? ? 前面講到,SDIO接口的wifi,首先,它是一個sdio的卡的設備,然后具備了wifi的功能,所以SDIO接口的WiFi驅(qū)動就是在wifi驅(qū)動外面套上了一個SDIO驅(qū)動的外殼,SDIO驅(qū)動仍然符合設備驅(qū)動的分層與分離思想


? ? ?設備驅(qū)動層(wifi 設備)

? ? ? ? ? ? ? ? ? ? ? |

核心層(向上向下提供接口)

? ? ? ? ? ? ? ? ? ? ? |

主機驅(qū)動層 (實現(xiàn)SDIO驅(qū)動)


? ? ? ? 下面先分析SDIO接口驅(qū)動的實現(xiàn),看幾個重要的數(shù)據(jù)結(jié)構(gòu)(用于核心層與主機驅(qū)動層 的數(shù)據(jù)交換處理)。

[ /include/linux/mmc/host.h ]

struct mmc_host ? ? 用來描述卡控制器

struct mmc_card ? ? 用來描述卡

struct mmc_driver ?用來描述 mmc 卡驅(qū)動

struct sdio_func ? ? ?用來描述 功能設備

struct mmc_host_ops ? 用來描述卡控制器操作接口函數(shù)功能,用于從 主機控制器層向 core 層注冊操作函數(shù),從而將core 層與具體的主機控制器隔離。也就是說 core 要操作主機控制器,就用這個 ops 當中給的函數(shù)指針操作,不能直接調(diào)用具體主控制器的函數(shù)。

? ? ? HOST層驅(qū)動分析在 前面的系列文章中?Linux SD卡驅(qū)動開發(fā)(二) —— SD 卡驅(qū)動分析HOST篇?有詳細闡述,下面只簡單回顧一下一些重要函數(shù)處理

1、編寫Host層驅(qū)動

? ? ?這里參考的是S3C24XX的HOST驅(qū)動程序 ? /drivers/mmc/host/s3cmci.c?

[cpp]?view plaincopy
  • static?struct?platform_driver?s3cmci_driver?=?{??
  • ?????.driver??=?{??
  • ?????????.name????=?"s3c-sdi",??//名稱和平臺設備定義中的對應??
  • ?????????.owner???=?THIS_MODULE,??
  • ?????????.pm??=?s3cmci_pm_ops,??
  • ?????},??
  • ?????.id_table?=?s3cmci_driver_ids,??
  • ?????.probe????????=?s3cmci_probe,??//平臺設備探測接口函數(shù)??
  • ?????.remove???????=?__devexit_p(s3cmci_remove),??
  • ?????.shutdown?=?s3cmci_shutdown,??
  • };??
  • ??
  • s3cmci_probe(struct?platform_device?*pdev)??
  • {??
  • ????//....??
  • ????struct?mmc_host?*mmc;??
  • ????mmc?=?mmc_alloc_host(sizeof(struct?s3cmci_host),?&pdev->dev);??//分配mmc_host結(jié)構(gòu)體??
  • ??
  • ????//.....??
  • }??
  • ??
  • /*注冊中斷處理函數(shù)s3cmci_irq,來處理數(shù)據(jù)收發(fā)過程引起的各種中斷*/??
  • request_irq(host->irq,?s3cmci_irq,?0,?DRIVER_NAME,?host)?//注冊中斷處理函數(shù)s3cmci_irq??
  • ??
  • /*注冊中斷處理s3cmci_irq_cd函數(shù),來處理熱撥插引起的中斷,中斷觸發(fā)的形式為上升沿、下降沿觸發(fā)*/??
  • request_irq(host->irq_cd,?s3cmci_irq_cd,IRQF_TRIGGER_RISING?|IRQF_TRIGGER_FALLING,?DRIVER_NAME,?host)??
  • ??
  • mmc_add_host(mmc);??//initialise?host?hardware?//向MMC?core注冊host驅(qū)動??
  • ---->?device_add(&host->class_dev);?//添加設備到mmc_bus_type總線上的設備鏈表中??
  • ---->?mmc_start_host(host);?//啟動mmc?host??
  • ??
  • /*MMC?drivers?should?call?this?when?they?detect?a?card?has?been?inserted?or?removed.檢測sd卡是否插上或移除*/??
  • ?---->mmc_detect_change(host,?0);??
  • ??
  • /*Schedule?delayed?work?in?the?MMC?work?queue.調(diào)度延時工作隊列*/??
  • ?mmc_schedule_delayed_work(&host->detect,?delay);??
  • 搜索host->detected得到以下信息:

    [/drivers/mmc/core/host.c]

    [cpp]?view plaincopy
  • NIT_DELAYED_WORK(&host->detect,?mmc_rescan);??
  • ??
  • mmc_rescan(struct?work_struct?*work)??
  • ---->mmc_bus_put(host);//card?從bus上移除時,釋放它占有的總線空間??
  • ??
  • /*判斷當前mmc?host控制器是否被占用,當前mmc控制器如果被占用,那么??host->claimed?=?1;否則為0?
  • ?*如果為1,那么會在while(1)循環(huán)中調(diào)用schedule切換出自己,當占用mmc控制器的操作完成之后,執(zhí)行?*mmc_release_host()的時候,會激活登記到等待隊列&host->wq中的其他?程序獲得mmc主控制器的使用權(quán)?
  • ?*/??
  • mmc_claim_host(host);??
  • ?????mmc_rescan_try_freq(host,?max(freqs[i],?host->f_min);??
  • ??
  • static?int?mmc_rescan_try_freq(struct?mmc_host?*host,?unsigned?freq)??
  • {??
  • ?????…??
  • ?????/*?Order's?important:?probe?SDIO,?then?SD,?then?MMC?*/??
  • ?????if?(!mmc_attach_sdio(host))??
  • ??????????return?0;??
  • ?????if?(!mmc_attach_sd(host))??
  • ?????????return?0;??
  • ?????if?(!mmc_attach_mmc(host))??
  • ?????????return?0;??
  • ????????….??
  • }??
  • ??
  • mmc_attach_sdio(struct?mmc_host?*host)??//匹配sdio接口卡??
  • ?????--->mmc_attach_bus(host,?&mmc_sdio_ops);??
  • ??
  • /*當card與總線上的驅(qū)動匹配,就初始化card*/??
  • mmc_sdio_init_card(host,?host->ocr,?NULL,?0);???
  • ????--->card?=?mmc_alloc_card(host,?NULL);//分配一個card結(jié)構(gòu)體??
  • ??????????mmc_set_bus_mode(host,?MMC_BUSMODE_PUSHPULL);?//設置mmc_bus的工作模式??
  • ??
  • struct?sdio_func?*sdio_func[SDIO_MAX_FUNCS];?//SDIO?functions?(devices)??
  • ??
  • sdio_init_func(host->card,?i?+?1);??
  • ????--->func?=?sdio_alloc_func(card);?//分配struct?sdio_fun(sdio功能設備)結(jié)構(gòu)體??
  • ??????????mmc_io_rw_direct();??
  • ??????????card->sdio_func[fn?-?1]?=?func;??
  • ??
  • mmc_add_card(host->card);??//將具體的sdio設備掛載到mmc_bus_types?總線??
  • sdio_add_func(host->card->sdio_func[i]);?//將sdio功能設備掛載到sdio_bus_types總線??
  • 這里一系列函數(shù)調(diào)用在前面的SD驅(qū)動蚊帳中已經(jīng)闡述過了,不再詳細闡述


    2、SDIO設備的熱插拔

    ? ? ? 當插拔SDIO設備,會觸發(fā)中斷通知到CPU,然后執(zhí)行卡檢測中斷處理函數(shù)在這個中斷服務函數(shù)中,mmc_detect_change->mmc_schedule_delayed_work(&host->detect,delay), INIT_DELAYED_WORK(&host->detect, mmc_rescan)會調(diào)度mmc_rescan函數(shù)延時調(diào)度工作隊列,這樣也會觸發(fā)SDIO設備的初始化流程,檢測到有效的SDIO設備后,會將它注冊到系統(tǒng)中去。

    [cpp]?view plaincopy
  • static?irqreturn_t?s3cmci_irq_cd(int?irq,?void?*dev_id)??
  • {??
  • ?????struct?s3cmci_host?*host?=?(struct?s3cmci_host?*)dev_id;??
  • ?????........??
  • ?????mmc_detect_change(host->mmc,?msecs_to_jiffies(500));??
  • ??
  • ?????return?IRQ_HANDLED;??
  • }??

  • 三、wifi 驅(qū)動部分解析

    wifi驅(qū)動的通用的軟件架構(gòu)

    1. 分為兩部分,上面為主機端驅(qū)動,下面是我們之前所說的firmware

    2. 其中固件部分的主要工作是:因為天線接受和發(fā)送回來的都是802.11幀的幀,而主機接受和傳送出來的數(shù)據(jù)都必須是802.3的幀,所以必須由firmware來負責802.3的幀和802.11幀之間的轉(zhuǎn)換

    3. 當天線收到數(shù)據(jù),并被firmware處理好后會放在一個buffer里,并產(chǎn)生一個中斷,主機在收到中斷后就去讀這個buffer。

    ? ? ??

    ? ? ?SDIO設備的驅(qū)動由sdio_driver結(jié)構(gòu)體定義,sdio_driver其實是driver的封裝。通過sdio_register_driver函數(shù)將SDIO設備驅(qū)動加載進內(nèi)核,其實就是掛載到sdio_bus_type總線上去。

    1、設備驅(qū)動的注冊與匹配

    [Drivers/net/wireless/libertas/if_sdio.c]

    [cpp]?view plaincopy
  • /*?SDIO?function?device?driver*/??
  • ??
  • struct?sdio_driver?{??
  • ?????char?*name;??//設備名??
  • ?????const?struct?sdio_device_id?*id_table;?//設備驅(qū)動ID??
  • ?????int?(*probe)(struct?sdio_func?*,?const?struct?sdio_device_id?*);//匹配函數(shù)??
  • ?????void?(*remove)(struct?sdio_func?*);??
  • ?????struct?device_driver?drv;??
  • };??
  • 下面是具體函數(shù)的填充:

    [cpp]?view plaincopy
  • /*if_sdio.c*/??
  • ??
  • static?struct?sdio_driver?if_sdio_driver?=?{??
  • ?????.name?????????=?"libertas_sdio",??
  • ?????.id_table?=?if_sdio_ids,??//用于設備與驅(qū)動的匹配??
  • ?????.probe????????=?if_sdio_probe,??
  • ?????.remove???????=?if_sdio_remove,??
  • ?????.drv?=?{??
  • ?????????.pm?=?&if_sdio_pm_ops,??
  • ?????????}??
  • };??
  • 設備注冊函數(shù)

    [cpp]?view plaincopy
  • /**?
  • ?*???sdio_register_driver?-?register?a?function?driver?
  • ?*???@drv:?SDIO?function?driver?
  • ?*/??
  • ??
  • int?sdio_register_driver(struct?sdio_driver?*drv)??
  • {??
  • ?????drv->drv.name?=?drv->name;??
  • ?????drv->drv.bus?=?&sdio_bus_type;??//設置driver的bus為sdio_bus_type??
  • ?????return?driver_register(&drv->drv);??
  • }??
  • 總線函數(shù)

    [cpp]?view plaincopy
  • 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,??
  • };??
  • 注意:設備或者驅(qū)動注冊到系統(tǒng)中的過程中,都會調(diào)用相應bus上的匹配函數(shù)來進行匹配合適的驅(qū)動或者設備,對于sdio設備的匹配是由sdio_bus_matchsdio_bus_probe函數(shù)來完成。

    [cpp]?view plaincopy
  • static?int?sdio_bus_match(struct?device?*dev,?struct?device_driver?*drv)??
  • {??
  • ?????struct?sdio_func?*func?=?dev_to_sdio_func(dev);??
  • ?????struct?sdio_driver?*sdrv?=?to_sdio_driver(drv);???
  • ?????if?(sdio_match_device(func,?sdrv))??
  • ?????????return?1;???
  • ??
  • ?????return?0;??
  • }??
  • ??
  • static?const?struct?sdio_device_id?*sdio_match_device(struct?sdio_func?*func,??
  • ?????struct?sdio_driver?*sdrv)??
  • {??
  • ?????const?struct?sdio_device_id?*ids;??
  • ?????ids?=?sdrv->id_table;?????????????
  • ??
  • ????if?(sdio_match_one(func,?ids))??
  • ???????????????????return?ids;??
  • }??
  • 由以上匹配過程來看,通過匹配id_table 和 sdio_driver設備驅(qū)動中id,來匹配合適的驅(qū)動或設備。最終會調(diào)用.probe函數(shù),來完成相關操作。


    2、If_sdio_probe函數(shù)

    ? ? 當檢測到sdio卡插入了之后就會調(diào)用If_sdio_probe,而當卡被移除后就會調(diào)用If_sdio_remove



    下面先看下If_sdio_probet函數(shù),if_sdio_prob 函數(shù) 主要做了兩件事 ?

    [cpp]?view plaincopy
  • static?struct?sdio_driver?if_sdio_driver?=?{??
  • ?.name??=?"libertas_sdio",??
  • ?.id_table?=?if_sdio_ids,???//用于設備和驅(qū)動的匹配??
  • ?.probe??=?if_sdio_probe,??
  • ?.remove??=?if_sdio_remove,??
  • ?.drv?=?{??
  • ??.pm?=?&if_sdio_pm_ops,??
  • ?},??
  • };??
  • ???
  • ??
  • 1?//定義一個?if_sdio??card的結(jié)構(gòu)體??
  • ?struct?if_sdio_card?*card;??
  • ?struct?if_sdio_packet?*packet;??//sdio?包的結(jié)構(gòu)體???
  • ?struct?mmc_host?*host?=?func->card->host;??
  • ??
  • ?//?查詢是否有指定的功能寄存器在mmc??
  • ???//_sdio_card中??
  • ?for?(i?=?0;i?<?func->card->num_info;i++)?{??
  • ??if?(sscanf(func->card->info[i],??
  • ????"802.11?SDIO?ID:?%x",?&model)?==?1)??
  • ???
  • //在這里進行片選??選擇到我們使用的marvell?8686?的設備??
  • case?MODEL_8686:??
  • ??card->scratch_reg?=?IF_SDIO_SCRATCH;??
  • ???
  • ???
  • //創(chuàng)建sdio?的工作隊列???
  • card->workqueue?=?create_workqueue("libertas_sdio");??
  • //調(diào)用下面的函數(shù)??
  • INIT_WORK(&card->packet_worker,?if_sdio_host_to_card_worker);??
  • ??
  • ??
  • //主機到卡的工作隊列??
  • static?void?if_sdio_host_to_card_worker(struct?work_struct?*work)??
  • ??
  • ?/*?Check?if?we?support?this?card??選擇我們所支持的卡的類型*/??
  • ??//賦值為sd8686_helper.bin???sd8686.bin??
  • /*fw_table?中的??MODEL_8686,?"sd8686_helper.bin",?"sd8686.bin"?},?/??
  • ?for?(i?=?0;?i?<?ARRAY_SIZE(fw_table);?i++)?{??
  • ??????if?(card->model?==?fw_table[i].model)??
  • ???????????break;??
  • ?}??
  • ?{?MODEL_8688,?"libertas/sd8688_helper.bin",?"libertas/sd8688.bin"?},??
  • ???
  • ??
  • //申請一個host??
  • sdio_claim_host(func);??
  • //使能sdio?的功能?寄存器??
  • ret?=?sdio_enable_func(func);??
  • if?(ret)??
  • ??goto?release;??
  • ??
  • 2//申請?sdio?的中斷??當有數(shù)據(jù)??,命令?或者是事件?的時間執(zhí)行中斷??
  • ret?=?sdio_claim_irq(func,?if_sdio_interrupt);??
  • ret?=?if_sdio_card_to_host(card);??//從無線網(wǎng)卡接收到數(shù)據(jù)?或者說是上報數(shù)據(jù)??
  • ret?=?if_sdio_handle_data(card,?card->buffer?+?4,?chunk?-?4);???//接收數(shù)據(jù)的處理???
  • ret?=?if_sdio_handle_cmd(card,?card->buffer?+?4,?chunk?-?4);???//處理申請的命令中斷??
  • ret?=?if_sdio_handle_event(card,?card->buffer?+?4,?chunk?-?4);//處理申請的事件中斷??
  • ??
  • ??
  • //添加網(wǎng)絡結(jié)構(gòu)體??分配設備并注冊??
  • priv?=?lbs_add_card(card,?&func->dev);??
  • ??
  • //分配Ethernet設備并注冊???
  • ?wdev?=?lbs_cfg_alloc(dmdev);??
  • //802無線網(wǎng)的具體的操作函數(shù)???
  • wdev->wiphy?=?wiphy_new(&lbs_cfg80211_ops,?sizeof(struct?lbs_private));??
  • ??
  • ???
  • //分配網(wǎng)絡設備是整個網(wǎng)絡部分操作的??
  • //的核心結(jié)構(gòu)體??
  • dev?=?alloc_netdev(0,?"wlan%d",?ether_setup);??//實例化wlan0的屬性??
  • dev->ieee80211_ptr?=?wdev;??
  • ?dev->ml_priv?=?priv;??
  • ?//設置設備的物理地址???
  • ?SET_NETDEV_DEV(dev,?dmdev);??
  • ?wdev->netdev?=?dev;??
  • ?priv->dev?=?dev;??
  • ???//初始化網(wǎng)絡設備?ops.??看門狗????
  • ??dev->netdev_ops?=?&lbs_netdev_ops;????//網(wǎng)絡設備的具體的操作函數(shù)???
  • ?dev->watchdog_timeo?=?5?*?HZ;??
  • ?dev->ethtool_ops?=?&lbs_ethtool_ops;?????
  • ?dev->flags?|=?IFF_BROADCAST?|?IFF_MULTICAST;??//廣播或者多播??
  • ???
  • ???
  • ???
  • ?//啟動一個內(nèi)核線程來管理這個網(wǎng)絡設備的數(shù)據(jù)發(fā)送,事件的處理(卡的拔出)和一些命令的處理???
  • ?priv->main_thread?=?kthread_run(lbs_thread,?dev,?"lbs_main");??
  • //初始化相關的工作隊列??
  • ?priv->work_thread?=?create_singlethread_workqueue("lbs_worker");??
  • ?INIT_WORK(&priv->mcast_work,?lbs_set_mcast_worker);??
  • ?priv->wol_criteria?=?EHS_REMOVE_WAKEUP;??
  • ?priv->wol_gpio?=?0xff;??
  • ?priv->wol_gap?=?20;??
  • ?priv->ehs_remove_supported?=?true;??
  • ???
  • ???
  • ?//設置私有變量???
  • //設置主機發(fā)送數(shù)據(jù)到卡??
  • ?priv->hw_host_to_card?=?if_sdio_host_to_card;??
  • ?priv->enter_deep_sleep?=?if_sdio_enter_deep_sleep;??
  • ?priv->exit_deep_sleep?=?if_sdio_exit_deep_sleep;??
  • ?priv->reset_deep_sleep_wakeup?=?if_sdio_reset_deep_sleep_wakeup;??
  • ?sdio_claim_host(func);????
  • ??
  • ??//啟動卡設備???
  • ?ret?=?lbs_start_card(priv);??
  • ?if?(lbs_cfg_register(priv))???
  • ??
  • ?ret?=?register_netdev(priv->dev);??
  • ?err?=?register_netdevice(dev);??
  • ??
  • ???
  • //具體的wifi設備驅(qū)動功能???
  • //網(wǎng)絡設備操作的具體函數(shù)???
  • static?const?struct?net_device_ops?lbs_netdev_ops?=?{??
  • ?.ndo_open???=?lbs_dev_open,???//打開??
  • ?.ndo_stop??=?lbs_eth_stop,??//停止??
  • ?.ndo_start_xmit??=?lbs_hard_start_xmit,???//開始發(fā)送數(shù)據(jù)??
  • ?.ndo_set_mac_address?=?lbs_set_mac_address,???//設置mac地址???
  • ?.ndo_tx_timeout??=?lbs_tx_timeout,????//發(fā)送超時??
  • ?.ndo_set_multicast_list?=?lbs_set_multicast_list,???//多播地址??
  • ?.ndo_change_mtu??=?eth_change_mtu,??//最大傳輸單元??
  • ?.ndo_validate_addr?=?eth_validate_addr,??//判斷地址的有效性???

  • 3、數(shù)據(jù)的接收,通過中斷的方式來解決

    ??? ?網(wǎng)絡設備接收數(shù)據(jù)的主要方法是由中斷引發(fā)設備的中斷處理函數(shù),中斷處理函數(shù)判斷中斷的類型,如果為接收中斷,則讀取接收到的數(shù)據(jù),分配sk_buff數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)緩沖區(qū),并將接收的數(shù)據(jù)復制到數(shù)據(jù)緩存區(qū),并調(diào)用netif_rx()函數(shù)將sk_buff傳遞給上層協(xié)議。

    ? ? 搜索if_sdio_interrupt,可知道它是在if_sdio.c文件中if_sdio_probe()函數(shù)中sdio_claim_irq(func, if_sdio_interrupt) ,func->irq_handler = if_sdio_interrupt。當s3cmci_irq中斷處理函數(shù)的S3C2410_SDIIMSK_SDIOIRQ 中斷被觸發(fā)時將調(diào)用if_sdio_interrupt()函數(shù),進行接收數(shù)據(jù)。

    [cpp]?view plaincopy
  • static?void?if_sdio_interrupt(struct?sdio_func?*func)??
  • ??
  • ret?=?if_sdio_card_to_host(card);??//從無線網(wǎng)卡接收到數(shù)據(jù)?或者說是上報數(shù)據(jù)??
  • //讀取端口上的數(shù)據(jù)?,放到card的buffer中???
  • ?ret?=?sdio_readsb(card->func,?card->buffer,?card->ioport,?chunk);??
  • 1.在這里一方面處理中斷??還有2???
  • ?switch?(type)?{???//處理cmd???data??event的請求???
  • ?case?MVMS_CMD:??
  • ??ret?=?if_sdio_handle_cmd(card,?card->buffer?+?4,?chunk?-?4);???//處理申請的命令中斷??
  • ??if?(ret)??
  • ???goto?out;??
  • ??break;??
  • ?case?MVMS_DAT:??
  • ??ret?=?if_sdio_handle_data(card,?card->buffer?+?4,?chunk?-?4);//處理申請的數(shù)據(jù)中斷???
  • ??if?(ret)??
  • ???goto?out;??
  • ??break;??
  • ?case?MVMS_EVENT:??
  • ??ret?=?if_sdio_handle_event(card,?card->buffer?+?4,?chunk?-?4);//處理申請的事件中斷??
  • ???
  • //讀取包的過程???
  • ?lbs_process_rxed_packet(card->priv,?skb);??
  • ???
  • ?//如果是中斷?,就把skb這個包提交給協(xié)議層,這個函數(shù)是??
  • ?//協(xié)議層提供的??netif_rx(skb)??
  • ?if?(in_interrupt())??
  • ??netif_rx(skb);????//提交給協(xié)議層???
  • ???
  • ???
  • 2//讀取端口上的數(shù)據(jù)?,放到card的buffer中???
  • ?ret?=?sdio_readsb(card->func,?card->buffer,?card->ioport,?chunk);??
  • //讀取地址,目的地址,數(shù)量?等??
  • int?sdio_readsb(struct?sdio_func?*func,?void?*dst,?unsigned?int?addr,?int?count)??
  • ??
  • ?????????return?sdio_io_rw_ext_helper(func,?0,?addr,?0,?dst,?count);??
  • ??
  • ????????????????ret?=?mmc_io_rw_extended(func->card,?write,func->num,?addr,?incr_addr,?buf,blocks,?func->cur_blksize);??
  • ?????????????????????????cmd.arg?=?write???0x80000000?:?0x00000000;??
  • ??????????????????????????????????
  • ????????????????????//wait?for??request????
  • ?????????????????????mmc_wait_for_req(card->host,?&mrq);??
  • ????????????????????????開始應答???
  • ?????????????????????????mmc_start_request(host,?mrq);??
  • ?????????????????????????wait_for_completion(&complete);??
  • ??????????????????????????????????????
  • ?????????????????????????????host->ops->request(host,?mrq);??

  • 4、 數(shù)據(jù)發(fā)送

    [cpp]?view plaincopy
  • //IP層通過dev_queue_xmit()將數(shù)據(jù)交給網(wǎng)絡設備協(xié)議接口層,網(wǎng)絡接口層通過netdevice中的注冊函數(shù)的數(shù)據(jù)發(fā)送函數(shù)??
  • int?dev_queue_xmit(struct?sk_buff?*skb)??
  • ??
  • ????if?(!netif_tx_queue_stopped(txq))?{??
  • ????__this_cpu_inc(xmit_recursion);??
  • ???//設備硬件開始發(fā)送????
  • ????rc?=?dev_hard_start_xmit(skb,?dev,?txq);??
  • ??//調(diào)用wifi網(wǎng)絡中的ops???
  • ??
  • ??rc?=?ops->ndo_start_xmit(skb,?dev);??
  • ??
  • ??dev->netdev_ops?=?&lbs_netdev_ops;????//設備的操作函數(shù)???
  • ??
  • ?//處理sdio?firware數(shù)據(jù)和內(nèi)核的數(shù)據(jù)main_thread?主線程????
  • ?priv->main_thread?=?kthread_run(lbs_thread,?dev,?"lbs_main");??
  • ??
  • ???//調(diào)用host_to_card???即if_sdio_card_to_host函數(shù)。???
  • ???int?ret?=?priv->hw_host_to_card(priv,?MVMS_DAT,priv->tx_pending_buf,priv->tx_pending_len);??
  • 為什么是if_sdio_to_host呢??因為在prob函數(shù)中定義了這一個??
  • //設置主機發(fā)送數(shù)據(jù)到卡??
  • ?priv->hw_host_to_card?=?if_sdio_host_to_card;??
  • ?????
  • static?int?if_sdio_host_to_card(struct?lbs_private?*priv,u8?type,?u8?*buf,?u16?nb)??
  • ??????//把buf中的數(shù)據(jù)?copy到sdio?包中,在對sdio?的包進行處理??
  • ?????????memcpy(packet->buffer?+?4,?buf,?nb);??
  • //創(chuàng)建工作隊列????
  • ?????????queue_work(card->workqueue,?&card->packet_worker);??
  • ?//初始化隊列????
  • ?INIT_WORK(&card->packet_worker,?if_sdio_host_to_card_worker);??
  • ??
  • ?//sdio的寫數(shù)據(jù)?????
  • ???ret?=?sdio_writesb(card->func,?card->ioport,?packet->buffer,?packet->nb);??
  • ?????????//mmc寫擴展口???
  • ???????????????ret?=?mmc_io_rw_extended(func->card,?write,func->num,?addr,?incr_addr,?buf,blocks,?func->cur_blksize);??
  • ??
  • ????????????????????//wait?for??request????
  • ?????????????????????????????????mmc_wait_for_req(card->host,?&mrq);??
  • ????????????????????????????????????
  • ?????????????????????????????mrq->done_data?=?&complete;??
  • ?????????????????????????????mrq->done?=?mmc_wait_done;??
  • ?????????????????????????????mmc_start_request(host,?mrq);??
  • ????????????????????????????????//完成等待?寫數(shù)據(jù)結(jié)束???
  • ?????????????????????????????wait_for_completion(&complete);??
  • ???
  • ???
  • ?????????????????????????????host->ops->request(host,?mrq);??
  • ???//到底結(jié)束??發(fā)送數(shù)據(jù)????

  • 5、移除函數(shù)

    ? ? ? ?當sdio卡拔除時,驅(qū)動會調(diào)用該函數(shù),完成相應操作。如釋放占有的資源,禁止func功能函數(shù),釋放host。

    [cpp]?view plaincopy
  • if_sdio_remove(struct?sdio_func?*func)??
  • ---->lbs_stop_card(card->priv);??
  • ?????lbs_remove_card(card->priv);??
  • ?????---->kthread_stop(priv->main_thread);??//終止內(nèi)核線程??
  • ??
  • ?????????lbs_free_adapter(priv);??
  • ?????????lbs_cfg_free(priv);??
  • ??????????free_netdev(dev);??
  • ??
  • ?????flush_workqueue(card->workqueue);??//刷新工作隊列??
  • ?????destroy_workqueue(card->workqueue);??
  • ?????sdio_claim_host(func);??
  • ?????sdio_release_irq(func);??
  • ?????sdio_disable_func(func);??
  • ??????sdio_release_host(func); ?
  • 總結(jié)

    以上是生活随笔為你收集整理的Linux 下wifi 驱动开发(三)—— SDIO接口WiFi驱动浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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