新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > Linux網卡驅動程序編寫

        Linux網卡驅動程序編寫

        作者: 時間:2012-05-09 來源:網絡 收藏

        與用戶模式下的malloc()不同,kmalloc()申請空間有大小限制。長度是2的整次方。可以申請的最大長度也有限制。另外kmalloc()有priority參數,通常使用時可以為GFP_KERNEL,如果在中斷里調用用GFP_ATOMIC參數,因為使用GFP_KERNEL則調用者可能進入sleep狀態,在處理中斷時是不允許的。

        本文引用地址:http://www.104case.com/article/149108.htm

        kfree()釋放的內存必須是kmalloc()申請的。如果知道內存的大小,也可以用kfree_s()釋放。

        2.4.2request_irq()、free_irq()

        這是申請中斷和釋放中斷的調用。在include/linux/sched.h里聲明。

        request_irq()調用的定義:

        intrequest_irq(unsignedintirq,

        void(*handler)(intirq,void*dev_id,structpt_regs*regs),

        unsignedlongirqflags,

        constchar*devname,

        void*dev_id);

        irq是要申請的硬件中斷號。在Intel平臺,范圍0--15。handler是向系統登記的中斷處理函數。這是一個回調函數,中斷發生時,系統調用這個函數,傳入的參數包括硬件中斷號,deviceid,寄存器值。dev_id就是下面的request_irq時傳遞給系統的參數dev_id。irqflags是中斷處理的一些屬性。比較重要的有SA_INTERRUPT,

        標明中斷處理程序是快速處理程序(設置SA_INTERRUPT)還是慢速處理程序(不設置SA_INTERRUPT)。快速處理程序被調用時屏蔽所有中斷。慢速處理程序不屏蔽。還有一個SA_SHIRQ屬性,設置了以后運行多個設備共享中斷。dev_id在中斷共享時會用到。一般設置為這個設備的device結構本身或者NULL。中斷處理程序可以用dev_id找到相應的控制這個中斷的設備,或者用irq2dev_map找到中斷對應的設備。

        voidfree_irq(unsignedintirq,void*dev_id);

        2.4.3時鐘

        時鐘的處理類似中斷,也是登記一個時間處理函數,在預定的時間過后,系統會調用這個函數。在include/linux/timer.h里聲明。

        structtimer_list{

        structtimer_list*next;

        structtimer_list*prev;

        unsignedlongexpires;

        unsignedlongdata;

        void(*function)(unsignedlong);

        };

        voidadd_timer(structtimer_list*timer);

        intdel_timer(structtimer_list*timer);

        voidinit_timer(structtimer_list*timer);

        使用時鐘,先聲明一個timer_list結構,調用init_timer對它進行初始化。

        time_list結構里expires是標明這個時鐘的周期,單位采用jiffies的單位。

        jiffies是一個全局變量,代表時間。它的單位隨硬件平臺的不同而不同。

        系統里定義了一個常數HZ,代表每秒種最小時間間隔的數目。這樣jiffies的單位就是1/HZ。Intel平臺jiffies的單位是1/100秒,這就是系統所能分辨的最小時間間隔了。所以expires/HZ就是以秒為單位的這個時鐘的周期。

        function就是時間到了以后的回調函數,它的參數就是timer_list中的data。data這個參數在初始化時鐘的時候賦值,一般賦給它設備的device結構指針。

        在預置時間到系統調用function,同時系統把這個time_list從定時隊列里清除。所以如果需要一直使用定時函數,要在function里再次調用add_timer()把這個timer_list加進定時隊列。

        2.4.4I/O

        I/O端口的存取使用:

        inlineunsignedintinb(unsignedshortport);

        inlineunsignedintinb_p(unsignedshortport);

        inlinevoidoutb(charvalue,unsignedshortport);

        inlinevoidoutb_p(charvalue,unsignedshortport);

        在include/adm/io.h里定義。

        inb_p()、outb_p()與inb()、outb_p()的不同在于前者在存取I/O時有等待(pause)一適應慢速的I/O設備。

        為了防止存取I/O時發生沖突,提供對端口使用情況的控制。在使用端口之前,可以檢查需要的I/O是否正在被使用,如果沒有,則把端口標記為正在使用,使用完后再釋放。系統提供以下幾個函數做這些工作。

        intcheck_region(unsignedintfrom,unsignedintextent);

        voidrequest_region(unsignedintfrom,unsignedintextent,constchar*name);

        voidrelease_region(unsignedintfrom,unsignedintextent);

        其中的參數from表示用到的I/O端口的起始地址,extent標明從from開始的端口數目。name為設備名稱。

        2.4.5中斷打開關閉

        系統提供給開放和關閉響應中斷的能力。是在include/asm/system.h中的兩個定義。

        #definecli()__asm____volatile__(cli::)

        #definesti()__asm____volatile__(sti::)

        2.4.6打印信息

        類似普通程序里的printf(),要輸出信息使用printk()。在include/linux/kernel.h里聲明。

        intprintk(constchar*fmt,...);

        其中fmt是格式化字符串。...是參數。都是和printf()格式一樣的。

        2.4.7注冊驅動程序

        如果使用模塊(module)方式加載驅動程序,需要在模塊初始化時把設備注冊到系統設備表里去。不再使用時,把設備從系統中卸除。定義在drivers/net/net_init.h里的兩個函數完成這個工作。

        intregister_netdev(structdevice*dev);

        voidunregister_netdev(structdevice*dev);

        dev就是要注冊進系統的設備結構指針。在register_netdev()時,dev結構一般填寫前面11項,即到init,后面的暫時可以不用初始化。最重要的是name指針和init方法。name指針空(NULL)或者內容為或者name[0]為空格(space),則系統把你的設備做為以太網設備處理。以太網設備有統一的命名格式,ethX。對以太網這么特別對待大概和的歷史有關。

        init方法一定要提供,register_netdev()會調用這個方法讓你對硬件檢測和設置。

        register_netdev()返回0表示成功,非0不成功。

        2.4.8sk_buff

        Linux網絡各層之間的數據傳送都是通過sk_buff。sk_buff提供一套管理緩沖區的方法,是Linux系統網絡高效運行的關鍵。每個sk_buff包括一些控制方法和一塊數據緩沖區。控制方法按功能分為兩種類型。一種是控制整個buffer鏈的方法,

        另一種是控制數據緩沖區的方法。sk_buff組織成雙向鏈表的形式,根據網絡應用的特點,對鏈表的操作主要是刪除鏈表頭的元素和添加到鏈表尾。sk_buff的控制

        linux操作系統文章專題:linux操作系統詳解(linux不再難懂)


        評論


        相關推薦

        技術專區

        關閉
        主站蜘蛛池模板: 黄大仙区| 金平| 呼图壁县| 府谷县| 梁平县| 湖州市| 呼伦贝尔市| 礼泉县| 乌鲁木齐县| 武清区| 大渡口区| 施秉县| 新昌县| 申扎县| 西平县| 宜宾市| 南丹县| 海林市| 榆中县| 灌南县| 思南县| 滁州市| 封开县| 大港区| 汉沽区| 北宁市| 徐汇区| 通城县| 平江县| 台南县| 城步| 乡宁县| 牙克石市| 塔河县| 鄂托克旗| 集安市| 迭部县| 兴宁市| 万安县| 达拉特旗| 固原市|