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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > linux >内容正文

linux

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

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

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

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

一、SDIO相關(guān)基礎(chǔ)知識(shí)解析

1、SDIO接口

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

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

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

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

· CMOS sensor card(照相模塊)?

· GPS card?

· GSM/GPRS modem card?

· Bluetooth card?

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


2、SDIO總線

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

CLK信號(hào):HOST給DEVICE的 時(shí)鐘信號(hào),每個(gè)時(shí)鐘周期傳輸一個(gè)命令。

CMD信號(hào):雙向 的信號(hào),用于傳送 命令 和 反應(yīng)。

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

VDD信號(hào):電源信號(hào)。

VSS1,VSS2:電源地信號(hào)。


3、SDIO熱插拔原理

方法:設(shè)置一個(gè)?定時(shí)器檢查?或?插拔中斷檢測(cè)

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

GPG10 為高電平 即沒(méi)有插入SD卡

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


4、SDIO命令

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

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

b -- Response:回應(yīng)是DEVICE返回的HOST的命令,作為Command的回應(yīng)。也是通過(guò)CMD線傳送的。

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

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

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

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


二、SDIO接口驅(qū)動(dòng)

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


? ? ?設(shè)備驅(qū)動(dòng)層(wifi 設(shè)備)

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

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

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

主機(jī)驅(qū)動(dòng)層 (實(shí)現(xiàn)SDIO驅(qū)動(dòng))


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

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

struct mmc_host ? ? 用來(lái)描述卡控制器

struct mmc_card ? ? 用來(lái)描述卡

struct mmc_driver ?用來(lái)描述 mmc 卡驅(qū)動(dòng)

struct sdio_func ? ? ?用來(lái)描述 功能設(shè)備

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

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

1、編寫(xiě)Host層驅(qū)動(dòng)

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

[cpp]?view plaincopy
  • static?struct?platform_driver?s3cmci_driver?=?{??
  • ?????.driver??=?{??
  • ?????????.name????=?"s3c-sdi",??//名稱和平臺(tái)設(shè)備定義中的對(duì)應(yīng)??
  • ?????????.owner???=?THIS_MODULE,??
  • ?????????.pm??=?s3cmci_pm_ops,??
  • ?????},??
  • ?????.id_table?=?s3cmci_driver_ids,??
  • ?????.probe????????=?s3cmci_probe,??//平臺(tái)設(shè)備探測(cè)接口函數(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)體??
  • ??
  • ????//.....??
  • }??
  • ??
  • /*注冊(cè)中斷處理函數(shù)s3cmci_irq,來(lái)處理數(shù)據(jù)收發(fā)過(guò)程引起的各種中斷*/??
  • request_irq(host->irq,?s3cmci_irq,?0,?DRIVER_NAME,?host)?//注冊(cè)中斷處理函數(shù)s3cmci_irq??
  • ??
  • /*注冊(cè)中斷處理s3cmci_irq_cd函數(shù),來(lái)處理熱撥插引起的中斷,中斷觸發(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注冊(cè)host驅(qū)動(dòng)??
  • ---->?device_add(&host->class_dev);?//添加設(shè)備到mmc_bus_type總線上的設(shè)備鏈表中??
  • ---->?mmc_start_host(host);?//啟動(dòng)mmc?host??
  • ??
  • /*MMC?drivers?should?call?this?when?they?detect?a?card?has?been?inserted?or?removed.檢測(cè)sd卡是否插上或移除*/??
  • ?---->mmc_detect_change(host,?0);??
  • ??
  • /*Schedule?delayed?work?in?the?MMC?work?queue.調(diào)度延時(shí)工作隊(duì)列*/??
  • ?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上移除時(shí),釋放它占有的總線空間??
  • ??
  • /*判斷當(dāng)前mmc?host控制器是否被占用,當(dāng)前mmc控制器如果被占用,那么??host->claimed?=?1;否則為0?
  • ?*如果為1,那么會(huì)在while(1)循環(huán)中調(diào)用schedule切換出自己,當(dāng)占用mmc控制器的操作完成之后,執(zhí)行?*mmc_release_host()的時(shí)候,會(huì)激活登記到等待隊(duì)列&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);??
  • ??
  • /*當(dāng)card與總線上的驅(qū)動(dòng)匹配,就初始化card*/??
  • mmc_sdio_init_card(host,?host->ocr,?NULL,?0);???
  • ????--->card?=?mmc_alloc_card(host,?NULL);//分配一個(gè)card結(jié)構(gòu)體??
  • ??????????mmc_set_bus_mode(host,?MMC_BUSMODE_PUSHPULL);?//設(shè)置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功能設(shè)備)結(jié)構(gòu)體??
  • ??????????mmc_io_rw_direct();??
  • ??????????card->sdio_func[fn?-?1]?=?func;??
  • ??
  • mmc_add_card(host->card);??//將具體的sdio設(shè)備掛載到mmc_bus_types?總線??
  • sdio_add_func(host->card->sdio_func[i]);?//將sdio功能設(shè)備掛載到sdio_bus_types總線??
  • 這里一系列函數(shù)調(diào)用在前面的SD驅(qū)動(dòng)蚊帳中已經(jīng)闡述過(guò)了,不再詳細(xì)闡述


    2、SDIO設(shè)備的熱插拔

    ? ? ? 當(dāng)插拔SDIO設(shè)備,會(huì)觸發(fā)中斷通知到CPU,然后執(zhí)行卡檢測(cè)中斷處理函數(shù)在這個(gè)中斷服務(wù)函數(shù)中,mmc_detect_change->mmc_schedule_delayed_work(&host->detect,delay), INIT_DELAYED_WORK(&host->detect, mmc_rescan)會(huì)調(diào)度mmc_rescan函數(shù)延時(shí)調(diào)度工作隊(duì)列,這樣也會(huì)觸發(fā)SDIO設(shè)備的初始化流程,檢測(cè)到有效的SDIO設(shè)備后,會(huì)將它注冊(cè)到系統(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ū)動(dòng)部分解析

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

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

    2. 其中固件部分的主要工作是:因?yàn)樘炀€接受和發(fā)送回來(lái)的都是802.11幀的幀,而主機(jī)接受和傳送出來(lái)的數(shù)據(jù)都必須是802.3的幀,所以必須由firmware來(lái)負(fù)責(zé)802.3的幀和802.11幀之間的轉(zhuǎn)換

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

    ? ? ??

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

    1、設(shè)備驅(qū)動(dòng)的注冊(cè)與匹配

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

    [cpp]?view plaincopy
  • /*?SDIO?function?device?driver*/??
  • ??
  • struct?sdio_driver?{??
  • ?????char?*name;??//設(shè)備名??
  • ?????const?struct?sdio_device_id?*id_table;?//設(shè)備驅(qū)動(dòng)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,??//用于設(shè)備與驅(qū)動(dòng)的匹配??
  • ?????.probe????????=?if_sdio_probe,??
  • ?????.remove???????=?if_sdio_remove,??
  • ?????.drv?=?{??
  • ?????????.pm?=?&if_sdio_pm_ops,??
  • ?????????}??
  • };??
  • 設(shè)備注冊(cè)函數(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;??//設(shè)置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,??
  • };??
  • 注意:設(shè)備或者驅(qū)動(dòng)注冊(cè)到系統(tǒng)中的過(guò)程中,都會(huì)調(diào)用相應(yīng)bus上的匹配函數(shù)來(lái)進(jìn)行匹配合適的驅(qū)動(dòng)或者設(shè)備,對(duì)于sdio設(shè)備的匹配是由sdio_bus_matchsdio_bus_probe函數(shù)來(lái)完成。

    [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;??
  • }??
  • 由以上匹配過(guò)程來(lái)看,通過(guò)匹配id_table 和 sdio_driver設(shè)備驅(qū)動(dòng)中id,來(lái)匹配合適的驅(qū)動(dòng)或設(shè)備。最終會(huì)調(diào)用.probe函數(shù),來(lái)完成相關(guān)操作。


    2、If_sdio_probe函數(shù)

    ? ? 當(dāng)檢測(cè)到sdio卡插入了之后就會(huì)調(diào)用If_sdio_probe,而當(dāng)卡被移除后就會(huì)調(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,???//用于設(shè)備和驅(qū)動(dòng)的匹配??
  • ?.probe??=?if_sdio_probe,??
  • ?.remove??=?if_sdio_remove,??
  • ?.drv?=?{??
  • ??.pm?=?&if_sdio_pm_ops,??
  • ?},??
  • };??
  • ???
  • ??
  • 1?//定義一個(gè)?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)??
  • ???
  • //在這里進(jìn)行片選??選擇到我們使用的marvell?8686?的設(shè)備??
  • case?MODEL_8686:??
  • ??card->scratch_reg?=?IF_SDIO_SCRATCH;??
  • ???
  • ???
  • //創(chuàng)建sdio?的工作隊(duì)列???
  • card->workqueue?=?create_workqueue("libertas_sdio");??
  • //調(diào)用下面的函數(shù)??
  • INIT_WORK(&card->packet_worker,?if_sdio_host_to_card_worker);??
  • ??
  • ??
  • //主機(jī)到卡的工作隊(duì)列??
  • 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"?},??
  • ???
  • ??
  • //申請(qǐng)一個(gè)host??
  • sdio_claim_host(func);??
  • //使能sdio?的功能?寄存器??
  • ret?=?sdio_enable_func(func);??
  • if?(ret)??
  • ??goto?release;??
  • ??
  • 2//申請(qǐng)?sdio?的中斷??當(dāng)有數(shù)據(jù)??,命令?或者是事件?的時(shí)間執(zhí)行中斷??
  • ret?=?sdio_claim_irq(func,?if_sdio_interrupt);??
  • ret?=?if_sdio_card_to_host(card);??//從無(wú)線網(wǎng)卡接收到數(shù)據(jù)?或者說(shuō)是上報(bào)數(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);???//處理申請(qǐng)的命令中斷??
  • ret?=?if_sdio_handle_event(card,?card->buffer?+?4,?chunk?-?4);//處理申請(qǐng)的事件中斷??
  • ??
  • ??
  • //添加網(wǎng)絡(luò)結(jié)構(gòu)體??分配設(shè)備并注冊(cè)??
  • priv?=?lbs_add_card(card,?&func->dev);??
  • ??
  • //分配Ethernet設(shè)備并注冊(cè)???
  • ?wdev?=?lbs_cfg_alloc(dmdev);??
  • //802無(wú)線網(wǎng)的具體的操作函數(shù)???
  • wdev->wiphy?=?wiphy_new(&lbs_cfg80211_ops,?sizeof(struct?lbs_private));??
  • ??
  • ???
  • //分配網(wǎng)絡(luò)設(shè)備是整個(gè)網(wǎng)絡(luò)部分操作的??
  • //的核心結(jié)構(gòu)體??
  • dev?=?alloc_netdev(0,?"wlan%d",?ether_setup);??//實(shí)例化wlan0的屬性??
  • dev->ieee80211_ptr?=?wdev;??
  • ?dev->ml_priv?=?priv;??
  • ?//設(shè)置設(shè)備的物理地址???
  • ?SET_NETDEV_DEV(dev,?dmdev);??
  • ?wdev->netdev?=?dev;??
  • ?priv->dev?=?dev;??
  • ???//初始化網(wǎng)絡(luò)設(shè)備?ops.??看門狗????
  • ??dev->netdev_ops?=?&lbs_netdev_ops;????//網(wǎng)絡(luò)設(shè)備的具體的操作函數(shù)???
  • ?dev->watchdog_timeo?=?5?*?HZ;??
  • ?dev->ethtool_ops?=?&lbs_ethtool_ops;?????
  • ?dev->flags?|=?IFF_BROADCAST?|?IFF_MULTICAST;??//廣播或者多播??
  • ???
  • ???
  • ???
  • ?//啟動(dòng)一個(gè)內(nèi)核線程來(lái)管理這個(gè)網(wǎng)絡(luò)設(shè)備的數(shù)據(jù)發(fā)送,事件的處理(卡的拔出)和一些命令的處理???
  • ?priv->main_thread?=?kthread_run(lbs_thread,?dev,?"lbs_main");??
  • //初始化相關(guān)的工作隊(duì)列??
  • ?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;??
  • ???
  • ???
  • ?//設(shè)置私有變量???
  • //設(shè)置主機(jī)發(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);????
  • ??
  • ??//啟動(dòng)卡設(shè)備???
  • ?ret?=?lbs_start_card(priv);??
  • ?if?(lbs_cfg_register(priv))???
  • ??
  • ?ret?=?register_netdev(priv->dev);??
  • ?err?=?register_netdevice(dev);??
  • ??
  • ???
  • //具體的wifi設(shè)備驅(qū)動(dòng)功能???
  • //網(wǎng)絡(luò)設(shè)備操作的具體函數(shù)???
  • static?const?struct?net_device_ops?lbs_netdev_ops?=?{??
  • ?.ndo_open???=?lbs_dev_open,???//打開(kāi)??
  • ?.ndo_stop??=?lbs_eth_stop,??//停止??
  • ?.ndo_start_xmit??=?lbs_hard_start_xmit,???//開(kāi)始發(fā)送數(shù)據(jù)??
  • ?.ndo_set_mac_address?=?lbs_set_mac_address,???//設(shè)置mac地址???
  • ?.ndo_tx_timeout??=?lbs_tx_timeout,????//發(fā)送超時(shí)??
  • ?.ndo_set_multicast_list?=?lbs_set_multicast_list,???//多播地址??
  • ?.ndo_change_mtu??=?eth_change_mtu,??//最大傳輸單元??
  • ?.ndo_validate_addr?=?eth_validate_addr,??//判斷地址的有效性???

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

    ??? ?網(wǎng)絡(luò)設(shè)備接收數(shù)據(jù)的主要方法是由中斷引發(fā)設(shè)備的中斷處理函數(shù),中斷處理函數(shù)判斷中斷的類型,如果為接收中斷,則讀取接收到的數(shù)據(jù),分配sk_buff數(shù)據(jù)結(jié)構(gòu)和數(shù)據(jù)緩沖區(qū),并將接收的數(shù)據(jù)復(fù)制到數(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。當(dāng)s3cmci_irq中斷處理函數(shù)的S3C2410_SDIIMSK_SDIOIRQ 中斷被觸發(fā)時(shí)將調(diào)用if_sdio_interrupt()函數(shù),進(jìn)行接收數(shù)據(jù)。

    [cpp]?view plaincopy
  • static?void?if_sdio_interrupt(struct?sdio_func?*func)??
  • ??
  • ret?=?if_sdio_card_to_host(card);??//從無(wú)線網(wǎng)卡接收到數(shù)據(jù)?或者說(shuō)是上報(bào)數(shù)據(jù)??
  • //讀取端口上的數(shù)據(jù)?,放到card的buffer中???
  • ?ret?=?sdio_readsb(card->func,?card->buffer,?card->ioport,?chunk);??
  • 1.在這里一方面處理中斷??還有2???
  • ?switch?(type)?{???//處理cmd???data??event的請(qǐng)求???
  • ?case?MVMS_CMD:??
  • ??ret?=?if_sdio_handle_cmd(card,?card->buffer?+?4,?chunk?-?4);???//處理申請(qǐng)的命令中斷??
  • ??if?(ret)??
  • ???goto?out;??
  • ??break;??
  • ?case?MVMS_DAT:??
  • ??ret?=?if_sdio_handle_data(card,?card->buffer?+?4,?chunk?-?4);//處理申請(qǐng)的數(shù)據(jù)中斷???
  • ??if?(ret)??
  • ???goto?out;??
  • ??break;??
  • ?case?MVMS_EVENT:??
  • ??ret?=?if_sdio_handle_event(card,?card->buffer?+?4,?chunk?-?4);//處理申請(qǐng)的事件中斷??
  • ???
  • //讀取包的過(guò)程???
  • ?lbs_process_rxed_packet(card->priv,?skb);??
  • ???
  • ?//如果是中斷?,就把skb這個(gè)包提交給協(xié)議層,這個(gè)函數(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);??
  • ????????????????????????開(kāi)始應(yīng)答???
  • ?????????????????????????mmc_start_request(host,?mrq);??
  • ?????????????????????????wait_for_completion(&complete);??
  • ??????????????????????????????????????
  • ?????????????????????????????host->ops->request(host,?mrq);??

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

    [cpp]?view plaincopy
  • //IP層通過(guò)dev_queue_xmit()將數(shù)據(jù)交給網(wǎng)絡(luò)設(shè)備協(xié)議接口層,網(wǎng)絡(luò)接口層通過(guò)netdevice中的注冊(cè)函數(shù)的數(shù)據(jù)發(fā)送函數(shù)??
  • int?dev_queue_xmit(struct?sk_buff?*skb)??
  • ??
  • ????if?(!netif_tx_queue_stopped(txq))?{??
  • ????__this_cpu_inc(xmit_recursion);??
  • ???//設(shè)備硬件開(kāi)始發(fā)送????
  • ????rc?=?dev_hard_start_xmit(skb,?dev,?txq);??
  • ??//調(diào)用wifi網(wǎng)絡(luò)中的ops???
  • ??
  • ??rc?=?ops->ndo_start_xmit(skb,?dev);??
  • ??
  • ??dev->netdev_ops?=?&lbs_netdev_ops;????//設(shè)備的操作函數(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呢??因?yàn)樵趐rob函數(shù)中定義了這一個(gè)??
  • //設(shè)置主機(jī)發(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?包中,在對(duì)sdio?的包進(jìn)行處理??
  • ?????????memcpy(packet->buffer?+?4,?buf,?nb);??
  • //創(chuàng)建工作隊(duì)列????
  • ?????????queue_work(card->workqueue,?&card->packet_worker);??
  • ?//初始化隊(duì)列????
  • ?INIT_WORK(&card->packet_worker,?if_sdio_host_to_card_worker);??
  • ??
  • ?//sdio的寫(xiě)數(shù)據(jù)?????
  • ???ret?=?sdio_writesb(card->func,?card->ioport,?packet->buffer,?packet->nb);??
  • ?????????//mmc寫(xiě)擴(kuò)展口???
  • ???????????????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);??
  • ????????????????????????????????//完成等待?寫(xiě)數(shù)據(jù)結(jié)束???
  • ?????????????????????????????wait_for_completion(&complete);??
  • ???
  • ???
  • ?????????????????????????????host->ops->request(host,?mrq);??
  • ???//到底結(jié)束??發(fā)送數(shù)據(jù)????

  • 5、移除函數(shù)

    ? ? ? ?當(dāng)sdio卡拔除時(shí),驅(qū)動(dòng)會(huì)調(diào)用該函數(shù),完成相應(yīng)操作。如釋放占有的資源,禁止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);??//刷新工作隊(duì)列??
  • ?????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驱动浅析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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