日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

ldd3之模塊學(xué)習(xí)總結(jié)(頁 1) - 文檔專區(qū) - 無分類文檔 - Linux論壇 - p...

 jijo 2009-04-28
china_long
ldd3之模塊學(xué)習(xí)總結(jié)

ldd3之模塊學(xué)習(xí)總結(jié)
  一個(gè)學(xué)習(xí)Linux設(shè)備驅(qū)動(dòng)程序都會(huì)碰到的第一個(gè)例程:
   
#include linux/init.h>
#include linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
    printk(KERN_ALERT "Hello, Tekkaman Ninja !\n");
    return 0;
}
static [color=#ff0000]void[/color] hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, Tekkaman Ninja !\n Love Linux !Love ARM ! Love KeKe !\n");
}
module_init(hello_init);
module_exit(hello_exit);

1、Makefile書寫:
   KERNELDIR = /usr/src/linux_2.6.26/linux-2.6.26 #內(nèi)核原代碼樹位置
   PWD = $(shell pwd)
   INSTALLDIR = /lib/modules/2.6.26linux2.6.26

   #1   obj-m := hello.o   模塊只有一個(gè)文件
   #2   obj-m := hello.o
        hello-objs := one.o two.o three.o  模塊有多個(gè)文件
   #3  如果模塊是由一個(gè)目錄(online)組成的寫法如下
        a、在這個(gè)目錄的上一級(jí)目錄中的makefile中加入
             [color=#000000]obj-m += online/  #告訴在編譯的時(shí)候找到online目錄[/color]
[color=#000000]             obj-$(CONFIG_USB_GADGET_ONLINE) += online/  這種方式是用配置選項(xiàng)(kconfig文件中添加配置選項(xiàng))來判斷是否編譯這個(gè)子目錄(即模塊)[/color]
[color=#000000]        b、最后,我們在online/下創(chuàng)建新文件Makefile,并且添加下面一行到其內(nèi)。
               obj-m += netmeeting.o[/color]
[color=#000000]               netmeeting-objs := one.o two.o three.o 如果有多個(gè)文件[/color]
    modules:
       [TAB] $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    modules_install:
       [TAB] cp hello.ko $(INSTALLDIR)      
    clean:
       [TAB] rm -rf *.o *.ko *.mod.c *.o.cmd .tmp_versions *.mod.o .cmd
    .PHONY :modules modules_install clean


   2、編譯運(yùn)行
      insmod
      rmmod
      lsmod
   3、調(diào)試查看輸出信息
      a、在模塊中添加調(diào)試輸出語句 printk  
           cat /proc/kmsg   (rsyslog沒有運(yùn)行)
           dmesg (syslogd進(jìn)程已經(jīng)運(yùn)行  /etc/rc.d/init/rsyslog 開啟)
           cat /var/log/message
      注意:
          [color=#000000]printk[/color]([color=#000000]KERN_ALERT[/color]"xxxx“);
宏的定義等級(jí)如下(printk.c):         
#define KERN_EMERG "" /* system is unusable   */
#define KERN_ALERT "" /* action must be taken immediately */
#define KERN_CRIT "" /* critical conditions   */
#define KERN_ERR "" /* error conditions   */
#define KERN_WARNING "" /* warning conditions   */
#define KERN_NOTICE "" /* normal but significant condition */
#define KERN_INFO "" /* informational   */
#define KERN_DEBUG "" /* debug-level messages   */

   當(dāng)指定的等級(jí)小于console_level(默認(rèn)4)時(shí)候,就可以直接在tty上面打印輸出語句
console_level設(shè)置方式:
    通過對/proc/sys/kernel/printk的訪問來改變[color=#000102]console_loglevel的值:[/color]
[Tekkaman2440@SBC2440V4]#echo 1 > /proc/sys/kernel/printk
[Tekkaman2440@SBC2440V4]#cat /proc/sys/kernel/printk
1       4       1       7
[Tekkaman2440@SBC2440V4]#insmod hello.ko
[Tekkaman2440@SBC2440V4]#rmmod hello
[Tekkaman2440@SBC2440V4]#echo 7 > /proc/sys/kernel/printk
[Tekkaman2440@SBC2440V4]#cat /proc/sys/kernel/printk7       4       1       7
[Tekkaman2440@SBC2440V4]#insmod hello.ko
Hello, Tekkaman Ninja !
[Tekkaman2440@SBC2440V4]#rmmod hello
Goodbye, Tekkaman Ninja !
Love Linux !Love ARM ! Love KeKe !
四個(gè)數(shù)字的含義:當(dāng)前的loglevel、默認(rèn)loglevel、最小允許的loglevel、引導(dǎo)時(shí)的默認(rèn)loglevel。
  
   4、模塊中使用的頭文件
      
#include linux/init.h>
#include linux/module.h>

  5、模塊中使用的描述性定義
   MODULE_AUTHOR("");
   MODULE_DESCRIPTION("");
   MODULE_VERSION("");
   MODULE_ALIAS("");
   MODULE_DEVICE_TABLE("");
    描繪性定義一般放在最后面

   6、模塊中的參數(shù)
    (內(nèi)核允許對驅(qū)動(dòng)程序指定參數(shù),而這些參數(shù)可在裝載驅(qū)動(dòng)程序模塊時(shí)改變[color=#000000]。 example : insmod hello-param.ko howmany=2 whom="KeKe" TNparam=4,3,2,1[/color])
     [color=#000000]對于如何向模塊傳遞參數(shù),Linux kernel 提供了一個(gè)簡單的框架。其允許驅(qū)動(dòng)程序聲明參數(shù),并且用戶在系統(tǒng)啟動(dòng)或模塊裝載時(shí)為參數(shù)指定相應(yīng)值,在驅(qū)動(dòng)程序里,參數(shù)的用法如同全局變量。這些模塊參數(shù)也能夠在sysfs中顯示出來。結(jié)果,有許許多多的方法用來創(chuàng)建和管理模塊參數(shù)。
    通過宏module_param()定義一個(gè)模塊參數(shù):
module_param(name, type, perm);
    這里,name既是用戶看到的參數(shù)名,又是模塊內(nèi)接受參數(shù)的變量; type表示參數(shù)的數(shù)據(jù)類型,是下列之一:byte, short, ushort, int, uint, long, ulong, charp, bool, invbool。這些類型分別是:a byte, a short integer, an unsigned short integer, an integer, an unsigned integer, a long integer, an unsigned long integer, a pointer to a char, a Boolean, a Boolean whose value is inverted from what the user specifies. The byte type is stored in a single char and the Boolean types are stored in variables of type int. The rest are stored in the corresponding primitive C types. 最后,perm指定了在sysfs中相應(yīng)文件的訪問權(quán)限。訪問權(quán)限用通常的八進(jìn)制格式來表示,例如,用0644(表示ower具有讀寫權(quán)限,group和everyone只讀權(quán)限), 或者用通常的S_Ifoo定義,例如,S_IRUGO | S_IWUSR (表示everyone具有讀權(quán)限,用戶具有寫權(quán)限)。用0表示完全關(guān)閉在sysfs中相對應(yīng)的項(xiàng)。
    其實(shí)宏不會(huì)聲明變量,因此在使用宏之前,必須聲明變量。所以,典型地用法如下:
static unsigned int use_acm = 0;   
module_param(use_acm, uint, S_IRUGO);
    這些必須寫在模塊源文件的開頭部分。即use_acm是全局的。
    我們也可以使模塊源文件內(nèi)部的變量名與外部的參數(shù)名有不同的名字。這通過宏module_param_named()定義。
module_param_named(name, variable, type, perm);
    這里name是外部可見的參數(shù)名,variable是源文件內(nèi)部的全局變量名。例如:
static unsigned int max_test = 9;
module_param_name(maximum_line_test, max_test, int, 0);
    如果模塊參數(shù)是一個(gè)字符串時(shí),通常使用charp類型定義這個(gè)模塊參數(shù)。內(nèi)核復(fù)制用戶提供的字符串到內(nèi)存,并且相對應(yīng)的變量指向這個(gè)字符串。例如:
static char *name;
module_param(name, charp, 0);
    另一種方法是通過宏module_param_string()讓內(nèi)核把字符串直接復(fù)制到程序中的字符數(shù)組內(nèi)。
module_param_string(name, string, len, perm);
    這里,name是外部的參數(shù)名,string是內(nèi)部的變量名,len是以string命名的buffer大?。梢孕∮赽uffer的大小,但是沒有意義),perm表示sysfs的訪問權(quán)限(或者perm是零,表示完全關(guān)閉相對應(yīng)的sysfs項(xiàng))。例如:
static char species[BUF_LEN];
module_param_string(specifies, species, BUF_LEN, 0);
    上面說得只是給模塊傳入一個(gè)參數(shù)的情況,如果給模塊傳入多個(gè)參數(shù),那該怎么辦呢?可以通過宏module_param_array()給模塊傳入多個(gè)參數(shù)。 用法如下:
module_param_array(name, type, nump, perm);
    這里,name既是外部模塊的參數(shù)名又是程序內(nèi)部的變量名,type是數(shù)據(jù)類型,perm是sysfs的訪問權(quán)限。指針nump指向一個(gè)整數(shù),其值表示有多少個(gè)參數(shù)存放在數(shù)組name中。值得注意是name數(shù)組必須靜態(tài)分配。例如:
static int finsh[MAX_FISH];
static int nr_fish;
module_param_array(fish, int, &nr_fish, 0444);
    通過宏module_param_array_named()使得內(nèi)部的數(shù)組名與外部的參數(shù)名有不同的名字。例如:
module_param_array_named(name, array, type, nump, perm);
    這里的參數(shù)意義與其它宏一樣。
    最后,通過宏MODULE_PARM_DESC()對參數(shù)進(jìn)行說明:
static unsigned short size = 1;
module_param(size, ushort, 0644);
MODULE_PARM_DESC(size, “The size in inches of the fishing pole” \
“connected to this computer.” );
    使用這些宏時(shí)需要包含頭文件。[/color]

[color=#ff0000]注意:[/color]
   由于模塊參數(shù)指的是外部向模塊傳遞參數(shù),模塊聲明的變量能否被內(nèi)核其他代碼和模塊使用呢?(是不是只要是非靜態(tài)的且導(dǎo)出符號(hào),內(nèi)核和其他模塊就能共享這個(gè)變量呢?)

  example code :
   
#include linux/init.h>
#include linux/module.h>
#include linux/moduleparam.h>
MODULE_LICENSE("Dual BSD/GPL");
static char *whom = "Tekkaman Ninja";
static int howmany = 1;
static int TNparam[] = {1,2,3,4};
static int TNparam_nr = 4;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);
module_param_array(TNparam , int , &TNparam_nr , S_IRUGO);
static int hello_init(void)
{
    int i;
    for (i = 0; i  howmany; i++)
        printk(KERN_ALERT "(%d) Hello, %s !\n", i, whom);
    for (i = 0; i ; i++)
        printk(KERN_ALERT "TNparam[%d] : %d \n", i, TNparam[i]);
    return 0;
}
static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, Tekkaman Ninja !\n Love Linux !Love ARM ! Love KeKe !\n");
}
module_init(hello_init);
module_exit(hello_exit);

編譯完成后
測試1
   insmod hello-param.ko howmany=2 whom="KeKe" TNparam=4,3,2,1
測試2
  [Tekkaman2440@SBC2440V4]#insmod hello-param.ko howmany=2 whom="KeKe"  TNparam=4,3,2,1,5,6,7,8
TNparam: can only take 4 arguments
hello_param: `4' invalid for parameter `TNparam'
insmod: cannot insert 'hello-param.ko': Invalid parameters (-1): Invalid argument
注意:
   這個(gè)測試說明module_param_array(TNparam , int , &TNparam_nr , S_IRUGO),參數(shù)[color=#ff0102]TNparam_nr不能自己限制參數(shù)的個(gè)數(shù),而需要程序員自己確定參數(shù)的個(gè)數(shù),否則數(shù)組[/color][color=#0000cc]TNparam可能會(huì)越界。(個(gè)人認(rèn)為如果傳送數(shù)組形式的參數(shù)最好再定義一個(gè)宏來確定數(shù)組的大小)[/color]

7、導(dǎo)出符號(hào)
  [color=#000000]  當(dāng)裝載模塊的時(shí)候,模塊動(dòng)態(tài)地鏈接入內(nèi)核之中。動(dòng)態(tài)鏈接的二進(jìn)制代碼只能調(diào)用外部函數(shù),然而,外部函數(shù)必須明確地輸出,在內(nèi)核中,通過EXPORT_SYMBOL()和EXPORT_SYMBOL_GPL來達(dá)到這個(gè)目的。
輸出的函數(shù)可以被其它模塊調(diào)用。沒有輸出過的函數(shù)不能被其它模塊調(diào)用。模塊比核心內(nèi)核映像代碼具有更嚴(yán)格的鏈接和調(diào)用規(guī)則。因?yàn)樗泻诵脑次募溄映梢粋€(gè)單一的作為基礎(chǔ)的映像,因此在內(nèi)核中核心代碼可以調(diào)用任何非靜態(tài)的接口。當(dāng)然,輸出符號(hào)也必須是非靜態(tài)屬性。
一套輸出的內(nèi)核符號(hào)稱之為輸出的內(nèi)核接口,甚至稱之為kernel API。
輸出一個(gè)內(nèi)核符號(hào)是舉手之勞之事。當(dāng)函數(shù)聲明之時(shí),在其后用EXPORT_SYMBOL()把函數(shù)輸出。
例如:
/* it will receive control requests including set_configuration(), which enables non-control requests.
*/
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{

}
EXPORT_SYMBOL(usb_gadget_register_driver) ;
    從此以后,任何模塊都可以調(diào)用函數(shù)usb_gadget_register_driver(),只要在源文件中包含聲明這個(gè)函數(shù)的頭文件,或者extern這個(gè)函數(shù)的聲明。
    有些開發(fā)者希望他們的接口只讓遵從GPL的模塊調(diào)用。通過MODULE_LICENSE()的使用,內(nèi)核鏈接器能夠強(qiáng)制保證做到這點(diǎn)。如果你希望前面的函數(shù)僅被標(biāo)有GPL許可證的模塊訪問,那么你可以用如下方式輸出符號(hào):
EXPORT_SYMBOL_GPL(usb_gadget_register_driver);
    如果你的代碼配置為模塊方式,那么必須確保:源文件中使用的所有接口必須是已經(jīng)輸出的符號(hào),否則導(dǎo)致在裝載時(shí)鏈接錯(cuò)誤。[/color]





[b]本文來自ChinaUnix博客,如果查看原文請點(diǎn):[/b][url]http://blog./u2/83200/showart_1679685.html[/url]

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請遵守用戶 評(píng)論公約

    類似文章 更多