精华内容
下载资源
问答
  • Linux下可以通过两种方式加载驱动程序:静态加载和动态加载。 静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用。动态加载利用了Linux的module特性,可以在系统启动后用insmod命令添加模块(.ko)...

    概述

    在咱们工作中,编译驱动,加载驱动时最常见的事。但是内核是如何加载驱动的,有些事编译到内核里面,有些事编译成ko,有些还能放到root下,让系统自动加载。

    总的说来,在Linux下可以通过两种方式加载驱动程序:静态加载和动态加载。

    静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用。动态加载利用了Linux的module特性,可以在系统启动后用insmod命令添加模块(.ko),在不需要的时候用rmmod命令卸载模块。

     

     

    驱动加载

    静态加载过程

     

    将模块的程序编译到Linux内核中,也就是咱们在编译内核时选择Y的模块,静态由do_initcall函数加载先来看看initcall在哪里:

    核心进程(/init/main.c)

    start_kernel()//内核启动的入口,负责初始化调度,中断,内存,最后启动1号进程 和2号进程

         rest_init()

              kernel_init()//这是谁? linux 1号进程,top一下系统就能找到1号进程了。

                  do_basic_setup()

                        do_initcalls()

     

    do_initcalls中会定义的各个模块加载顺序,加载顺序分为16个等级,加载时按照16个等级依次加载内核驱动。关于每个等级的定义参考/include/linux/init.h举个例子,在2.6.24的内核 中:gianfar_device使用的是arch_initcall,而gianfar_driver使用的是module_init,因为 arch_initcall的优先级大于module_init,所以gianfar设备驱动的device先于driver在总线上添加。

     

    动态加载过程

    将模块的程序编译成KO也就是咱们在编译内核时选择M的模块,通过insmod

    modprobe 或者udev动态加载到内核中 insmod绝对路径/××.ko,而modprobe ××即可,不用加.ko或.o后缀,也不用加路径;最重要的一点是:modprobe同时会加载当前模块所依赖的其它模块

    来看看insmod都做了什么:

    Insmod

        insmod_main

            bb_init_module

                init_module

                    sys_init_module进入系统调用

                          sys_init_module()系统调用会调用module_init指定的函数进行模块的初始化,至此ko加载完成。

     

     

    驱动匹配

    硬件固件设计

    以PCI为例,所有PCI硬件上必须设计一系列寄存器,PCI通过这些寄存器获取硬件信息,称为PCI配置空间,PCI配置空间格式如下:

     

    PCI标准规定每个设备的配置寄存器组最多可以有256字节的连续空间,其中开头的64字节的用途和格式是标准的,成为配置寄存器组的“头部”,这样的头部又有两种,“0型”头部用于一般的PCI设备,“1型”头部用于PCI桥,无论是“0型”还是“1型”,其开头的16个字节的用途和格式是共同的。其中Device ID 和 Vendor ID 位于前4个字节。

    在系统中运行LSPCI -NN,会得到类似如下输出:

     Ethernet controller [0200]: Intel Corporation 82545EM Gigabit Ethernet Controller (Copper) [8086:100f] (rev 01)

    其中的8086是vendor ID,100f是Device ID。所以咱们常用的LSCPI实质上就是去硬件上读取硬件的寄存器值,并且显示出来。

    软件驱动设计

    每一个硬件设备都有Verdon ID, Device ID, SubVendor ID等信息。所以每一个设备驱动程序,必须说明自己能够为哪些Verdon ID, DevieceID, SubVendor ID的设备提供服务。以PCI设备为例,它是通过一个pci_device_id的数据结构来实现这个功能的。例如:RTL8139驱动的pci_device_id定义为:

     

    Verdon ID可以理解为厂商ID,8086 代表Intel,1249代表三星等,Device ID可以理解为产品ID,每款产品的ID不同。上面的信息说明,Verdon ID为0x10EC, Device ID为0x8139, 0x8138的PCI设备(SubVendor ID和SubDeviceID为PCI_ANY_ID,表示不限制。),都可以使用这个驱动程序(8139too)。

    下面是内核设备与驱动匹配的代码:

     

    自动加载过程

    自动加载属于动态加载,加载的是ko文件,许多同学也没搞清楚,系统启动之后ko在什么时候,通过什么程序自动加载上的。

    构建自动加载环境

     

    编译内核时,通过make modules_install INSTALL_MOD_PATH=XXX,会将所有选项为M的模块编译为KO, 并且发布到xxx/lib/modules/uname-r/下面。在模块安装的时候,depmod会根据模块中的rtl8139_pci_tbl的信息,生成下面的信息,保存到/lib/modules/uname-r/modules.alias文件中,其内容如下:

     

    alias pci:v000010ECd00008138sv*sd*bc*sc*i* 8139too alias pci:v000010ECd00008139sv*sd*bc*sc*i* 8139too ......

     

    v后面的000010EC说明其Vendor ID为10EC,d后面的00008138说明Device ID为8139,而sv,和sd为SubVendor ID和SubDevice ID,后面的星号表示任意匹配。

    另外在/lib/modules/uname-r/modules.dep文件中还保存这模块之间的依赖关系,其内容如下:

     

    8139too.ko:mii.ko

     

    modules.dep由depmod工具生成,在使用 modprobe xxx加载驱动时, modprobe需要借助modules.dep文件来分析模块之间的依赖关系,先加载依赖的ko,再加载真正需要加载的ko。

     

     

    PCI扫描自动加载驱动

    在内核启动过程中,总线驱动程序会会总线协议进行总线枚举(总线驱动程序总是集成在内核之中,不能够按模块方式加载,你可以通过make menuconfig进入Busoptions,这里面的各种总线,你只能够选择Y或N,而不能选择M.),并且为每一个设备建立一个设备对象。每一个总线对象有一个kset对象,每一个设备对象嵌入了一个kobject对象,kobject连接在kset对象上,这样总线和总线之间,总线和设备设备之间就组织成一颗树状结构。当总线驱动程序为扫描到的设备建立设备对象时,会初始化kobject对象,并把它连接到设备树中,同时会调用kobject_uevent()把这个(添加新设备的)事件,以及相关信息(包括设备的VendorID,DeviceID等信息)通过netlink发送到用户态中。

    来看看这个过程:

    subsys_initcall (前面讲到过驱动的16级加载机制,subsys_initcall处于16级中的第8级,arch\x86\pci\legacy.c 参照内核4.19)

    pci_legacy_init

    pcibios_scan_root

    pci_scan_root_bus

    pci_scan_slot

    pci_scan_single_device

    pci_device_add

    device_add

     

    device_add有两个流程:

    1. bus_probe_device 匹配内核中已有驱动
    2. kobject_uevent 发消息到udev,让udev去/lib/modules/下面加载驱动

    在用户态的udevd检测到这个事件,就可以根据这些信息,打开/lib/modules/uname-r/modules.alias文件,根据

     

    alias pci:v000010ECd00008138sv*sd*bc*sc*i* 8139too

     

    得知这个新扫描到的设备驱动模块为8139too。于是modprobe就知道要加载8139too这个模块了,同时modprobe根据 modules.dep文件发现,8139too依赖于mii.ko,如果mii.ko没有加载,modprobe就先加载mii.ko,接着再加载 8139too.ko。

     

    展开全文
  • 1编写驱动程序driver_insmod.c 头文件   2 编写Makefile文件   pwd:当前所在路径 uname -r: 显示操作系统的发行版号 3 运行结果   4动态加载驱动 未安装前执行lsmod命令   安装驱动   安装...

    1编写驱动程序driver_insmod.c

    头文件

     

    2 编写Makefile文件

     

    pwd:当前所在路径

    uname -r: 显示操作系统的发行版号

    3 运行结果

     

    4动态加载驱动

    未安装前执行lsmod命令

     

    安装驱动

     

    安装完成后

    =

    4 测试程序

     

    5编译测试程序

     

     

    新建一个驱动文件,或者测试程序无法起作用

     

    执行测试程序driver_test.o

    再次执行lsmod

     

    6驱动程序编译进内核

    在drivers/目录下建一个drivertest文件夹将编写好的程序移到该文件夹。

     

    drivertest文件夹下新建KconfigMakefile文件。

    Makefile文件

     

    Kconfig文件

     

    修改drivers/Kconfig文件 

     

    修改drivers/Makefile 文件 

     

    执行make menuconfig命令

    出现的问题:

    1

     

     解决办法:   安装ncurses库。

    sudo apt-get install libncurses*

    2

     

    解决办法:把终端窗口扩大

     

     

     

    展开全文
  • 文章来源:...uk=2550302069 在LINUX加载驱动程序可以采用动态和静态两种方式。静态加载就是把驱动程序直接编译到内核里,系统启动后可以直接调用。静态加载的缺...

    文章来源:http://www.linuxdiyf.com/bbs/viewthread.php?tid=91244

    我的资料:http://pan.baidu.com/share/link?shareid=1965141339&uk=2550302069

    在LINUX下加载驱动程序可以采用动态和静态两种方式。静态加载就是把驱动程序直接编译到内核里,系统启动后可以直接调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译下载内核,效率较低。动态加载利用了LINUX的module特性,可以在系统启动后用insmod命令把驱动程序(.o文件)添加上去,在不需要的时候用rmmod命令来卸载。在台式机上一般采用动态加载的方式。在嵌入式产品里可以先用动态加载的方式来调试,调试完毕后再编译到内核里。下面以我们的nHD板卡为例讲述一下加载驱动程序的方法。
    假设我们需要添加一个名为mydrv的字符型设备驱动,主设备号为254,次设备号为0(只有一个从设备)。
    静态加载的步骤如下:
    1、编写自己的驱动程序源文件mydrv.c,并放在firmware\uClinux-Samsung-2500\linux-2.4.x\drivers\char下面。一个典型的字符型驱动的最后一般包括如下内容:
    static int mydrv_init(void)
    {
    int ret;
    ret = register_chrdev(mydrv_major, " mydrv ", &my_fops);
    if(ret == 0) printk("register_chrdev succeed!\n");
    else       printk("register_chrdev fail!\n");
        return 0;
    }
    static __exit void mydrv _cleanup(void)
    {
    unregister_chrdev(mydrv _major, " mydrv ");
    printk("register_chrdev succeed!\n");
    return ;
    }
    module_init(mydrv _init);
    module_exit (mydrv _cleanup);
    函数mydrv_init的任务是注册设备,mydrv_cleanup的任务是取消注册。 Module_init和module_exit的作用后面会讲到。
    2.在firmware\uClinux-Samsung-2500\vendors\Samsung\2500\Makefile中添加如下语句(以刚才的设备为例,实际添加时当然要根据你自己的设备名称和设备号来添加):
    mknod $(ROMFSDIR) /dev/mydrv c 254 0
    这句话的目的是在内核中创建一个与你的驱动程序对应的设备节点。
    3.在firmware\uClinux-Samsung-2500\linux-2.4.x\drivers\char\Makefile
    中添加如下语句:
    obj-$(CONFIG_CHAR_MYDRV) +=mydrv.o
    这句话的目的是根据编译选项$(CONFIG_CHAR_MYDRV)来决定是否要添加该设备驱动。
    4.在firmware\uClinux-Samsung-2500\linux-2.4.x\drivers\char\config.in
    中添加:
    if [“$CONFIG_ARCH_SAMSUNG”=”y”]; then
    tristate ' ,MYDRV driver module ' CONFIG_CHAR_MYDRV
    这句话的目的是在运行make menuconfig时产生与你的设备对应的编译选项。
    5.运行make menuconfgi,应该能看到你自己的设备的选项,选中就可以了。
    6.编译内核,下载,运行自己的测试程序。
    如果你觉得上述步骤比较麻烦,可以把4、5两条都省去,把第3条中的
    obj-$(CONFIG_CHAR_MYDRV) +=mydrv.o
    改为
    obj-y +=mydrv.o
    这样在menuconfig就没有与你的设备对应的选项了,编译内核时直接会把你的驱动编译进去。
    还有一个问题需要说明一下。在…/drivers/char下有一个mem.c文件,其中最后有一个int __init chr_dev_init(void)函数。大家可以看到,所有字符设备的初始化函数(IDE_INT_init之类)都要添加在这里,而我们刚才的驱动程序的初始化函数并没有添加到这里。这个问题涉及到系统启动时的do_initcall函数,详细讲述起来比较烦琐,大家有兴趣可以看一下《情景分析》下册P726~P729。这里简单介绍一下。如果对一个函数(通常都是一些初始化函数)作如下处理(仍以我们的mydrv_init函数为例):
    __initcall(mydrv_init)
    那么在编译内核时会生成一个指向mydrv_init的函数指针__initcall_mydrv_int,系统启动时,在运行do_initcall函数时,会依次执行这些初始化函数,并且会在初始化结束后把这些函数所占用的内存释放掉。
    回到mem.c文件,在最后有一行:
    __initcall(chr_dev_init)
    这句话的作用就显而易见了,在系统启动时自动执行chr_dev_init函数。所以我们完全可以不用在mem.c/chr_dev_init中添加我们自己的初始化函数,而是在我们自己的设备文件中(mydrv.c)添加如下一行:
    __initcall(mydrv_init).
    在我们前面说到的我们自己的设备文件mydrv.c中,最后有一句:
    module_init(mydrv _init);
    大家可以看一下module_init的定义,在…linux.-2.4.x\include\linux\init.h中。如果定义了宏MODULE时,module_init是作为模块初始化函数,如果没有定义MODULE,则
    module_init(fn)就被定义为__initcall(fn)。静态编译时是不定义MODULE的,所以我们的驱动中的module_init就等于是:
    __initcall(mydrv_init).
    这样我们的初始化函数就会在启动时被执行了。
    至于究竟是在mem.c/chr_dev_init中添加你的设备初始化函数,还是在设备文件中通过module_init来完成,完全取决于你的喜好,没有任何差别。如果你的初始化函数只是注册一个设备(没有申请内存等操作),那即使你在两个地方都加上(等于初始化了两次)也没关系,不会出错(有兴趣可以看一下内核里注册设备的函数实现,
    …linux-2.4.x\fs\devices.c\register_chrdev)。不过为了规范起见,还是不建议这样作。
    最后一个问题。在静态加载驱动的时候,我们那个mydrv_cleanup和module_exit函数永远不会被执行,所以去掉是完全可以的,不过为了程序看起来结构清晰,也为了与动态加载的程序兼容,还是建议保留着。
    下面讲一下动态加载驱动的方法。
    1、运行make menuconfgi,在内核配置中进入Loadable module support,选择Enable loadable module support和Kernel module loader(NEW)两个选项。在应用程序配置中进入busybox,选择insmod, rmmod, lsmod三个选项。
    2、在…vendors\Samsung\2500\Makefile中添加相应的设备节点,方法与静态加载时完全一样。
    3、编写自己的驱动程序文件,在文件开始处加一句:
    #define MODULE
    文件最后的
    mydrv_init
    mydrv_cleanup
    module_init(mydrv _init)
    module_exit (mydrv _cleanup)
    这四项必须保留。
    4、仿照如下的格式写自己的Makefile文件:
    KERNELDIR= /home/hexf/hardware/nHD/Design/firmware/uClinux-Samsung-2500/linux-2.4.x
    CFLAGS = -D__KERNEL__ -I$(KERNELDIR)/include       -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common -fno-common -pipe -fno-builtin -D__linux__ -DNO_MM -mapcs-32   -mshort-load-bytes -msoft-float
    CC   =   arm-elf-gcc
    all: mydrv.o
    clean:
    rm -f *.o
    5、编译自己的驱动程序文件。注意在动态加载时只编译不连接,所以得到的是.o文件。
    6、把编译后的驱动程序的.o 文件,连同自己的测试程序(假设叫mytest,注意这个是可执行文件)一起放在编译服务器的/exports/自己的目录下。测试程序就是一个普通的应用程序,其编写和编译的步骤这里就不讲了。
    7、启动nHD板卡,用nfs的方法把编译服务器上/exports/自己的目录mount上来(假设mount 到 /mnt下)。Nfs的使用大家都很熟悉了,这里就不再说。
    8、
    cd /mnt
    /bin/insmod mydrv.o
    现在你的设备就已经被动态加载到系统里了。可以用lsmod命令查看当前已挂接的模块。
    9、运行你的测试程序
    10、调试完毕后用 rmmod mydrv把你的设备卸载掉。
    补充几点:
    1、关于建立设备节点的问题,因为大家所使用的系统不太一样,所以不需要按照我说的方法。总之只要在你自己的系统的dev目录下建立了自己的驱动程序的设备节点就可以了。
    2、没有考虑动态分配主设备号的问题。所以注册设备那个地方稍微有点不严密。
    3、模块加载时要把自己的.c文件编译成.o文件,CFLAGS后面那一串编译选项有时可能有点烦人,如果你没搞定,最简单的办法就是重新编译一遍内核并重定向到一个文件中(别忘了先make clean一下):make > out。
    然后在out文件里随便找一个字符驱动程序的编译过程,把它的编译选项找出来,拷贝到你自己的Makefile里就可以了。我就是这么作的。
    下面是一个最简单的字符设备驱动的例子。实际的驱动千差万别,但其实也就是“填充”自己的open,close,read,write,ioctl几个函数而已。
    #ifndef __KERNEL__
    #define __KERNEL__
    #endif
    #define MODULE
    #define drvtest_major 254
    #include <linux/config.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/sched.h>
    #include <linux/kernel.h>     // printk()
    #include <linux/slab.h>     // kmalloc()
    #include <linux/errno.h>   // error codes
    #include <linux/types.h>   // size_t
    #include <linux/interrupt.h>   // mark_bh
    #include <linux/i2c.h>      
    #include <linux/skbuff.h>
    #include <asm/segment.h>
    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <linux/wait.h>
    #include <asm/arch/hardware.h>
    static int mytest_open(struct inode *inode,struct file *filp)
    {
    MOD_INC_USE_COUNT;
    printk("mytest open!\n");
    return 0;
    }
    static ssize_t mytest_read(struct file *flip,char * buff,size_t count,
            loff_t * f_pos)
    {
          char buf[10] ={0x1,0x2,0x3,0x4,0x5};
          memcpy(buff,buf,5);
          return 5;
    }
    static int mytest_close(struct inode *inode,struct file *filp)
    {   MOD_DEC_USE_COUNT;
    printk("mytest close!\n");
    return 0;
    }
    static struct file_operations my_fops = {
    read:   mytest_read,
    // write:   mytest_write,
    open:   mytest_open,
    release: mytest_close,
    // ioctl:   mytest_ioctl,
    };
    static int mytest_init(void)
    {
    int ret;
    ret = register_chrdev(drvtest_major, "drvtest", &my_fops);
    if(ret == 0) printk("register_chrdev succeed!\n");
    else       printk("register_chrdev fail!\n");
        return 0;
    }
    static __exit void mytest_cleanup(void)
    {
    unregister_chrdev(drvtest_major, "drvtest");
    printk("register_chrdev succeed!\n");
    printk("bye!\n");
        return ;
    }
    module_init(mytest_init);
    module_exit(mytest_cleanup);

    转载于:https://www.cnblogs.com/yuqilihualuo/p/3414543.html

    展开全文
  • uclinux下静态/动态加载驱动程序的方法说明:这是我最近给单位写的一篇文档,没有什么复杂的东东,对刚接触linuxdriver的朋友或许有点帮助。文档本来是针对我们自己的产品的,有些地方(路径、mknod、动态分配主设备...

    uclinux下静态/动态加载驱动程序的方法

    说明:这是我最近给单位写的一篇文档,没有什么复杂的东东,对刚接触linux

    driver的朋友或许有点帮助。文档本来是针对我们自己的产品的,有些地方(路径、mknod、动态分配主设备号等)本来应该改改,因为懒惰也没去改。     在LINUX下加载驱动程序可以采用动态和静态两种方式。静态加载就是把驱动程序直接编译到内核里,系统启动后可以直接调用。静态加载的缺点是调试起来比

    较麻烦,每次修改一个地方都要重新编译下载内核,效率较低。动态加载利用了LINUX的module特性,可以在系统启动后用insmod命令把驱动程序

    (.o文件)添加上去,在不需要的时候用rmmod命令来卸载。在台式机上一般采用动态加载的方式。在嵌入式产品里可以先用动态加载的方式来调试,调试完

    毕后再编译到内核里。    下面以我们的nHD板卡为例讲述一下加载驱动程序的方法。

    假设我们需要添加一个名为mydrv的字符型设备驱动,主设备号为254,次设备号为0(只有一个从设备)。静态加载的步骤如下: 1、编写自己的驱动程序源文件mydrv.c,并放在firmware\uClinux-Samsung-2500\linux-2.4.x            drivers\char下面。一个典型的字符型驱动的最后一般包括如下内容: static int mydrv_init(void)

    {   int ret;   ret = register_chrdev(mydrv_major, " mydrv ", &my_fops);

    if(ret == 0) printk("register_chrdev succeed!\n");   else

    printk("register_chrdev fail!\n");   return 0; }

    static __exit void mydrv _cleanup(void){    unregister_chrdev(mydrv _major, " mydrv ");  printk("register_chrdev

    succeed!\n");   return ; } module_init(mydrv _init); module_exit (mydrv _cleanup);

    函数mydrv_init的任务是注册设备,mydrv_cleanup的任务是取消注册。

    Module_init和module_exit的作用后面会讲到。

    2.在firmware\uClinux-Samsung-2500\vendors\Samsung\2500\Makefile中添加如下语句(以刚

    才的设备为例,实际添加时当然要根据你自己的设备名称和设备号来添加): mknod $(ROMFSDIR) /dev/mydrv c 254 0 .这句话的目的是在内核中创建一个与你的驱动程序对应的设备节点。

    3.在firmware\uClinux-Samsung-2500\linux-2.4.x\drivers\char\Makefile

    中添加如下语句: obj-$(CONFIG_CHAR_MYDRV) +=mydrv.o

    这句话的目的是根据编译选项$(CONFIG_CHAR_MYDRV)来决定是否要添加该设备驱动。4.在firmware\uClinux-Samsung-2500\linux-2.4.x\drivers\char\config.in

    中添加:

    if [“$CONFIG_ARCH_SAMSUNG”=”y”]; then

    tristate ' ,MYDRV driver module ' CONFIG_CHAR_MYDRV 这句话的目的是在运行make menuconfig时产生与你的设备对应的编译选项。5.运行make menuconfgi,应该能看到你自己的设备的选项,选中就可以了。6.编译内核,下载,运行自己的测试程序。 如果你觉得上述步骤比较麻烦,可以把4、5两条都省去,把第3条中的

    obj-$(CONFIG_CHAR_MYDRV) +=mydrv.o

    改为 obj-y +=mydrv.o 这样在menuconfig就没有与你的设备对应的选项了,编译内核时直接会把你的驱动编译进去。    还有一个问题需要说明一下。在…/drivers/char下有一个mem.c文件,其中最后有一个int __init

    chr_dev_init(void)函数。大家可以看到,所有字符设备的初始化函数(IDE_INT_init之类)都要添加在这里,而我们刚才的驱动

    程序的初始化函数并没有添加到这里。这个问题涉及到系统启动时的do_initcall函数,详细讲述起来比较烦琐,大家有兴趣可以看一下《情景分析》下

    册P726~P729。这里简单介绍一下。如果对一个函数(通常都是一些初始化函数)作如下处理(仍以我们的mydrv_init函数为例):

    __initcall(mydrv_init)

    那么在编译内核时会生成一个指向mydrv_init的函数指针__initcall_mydrv_int,系统启动时,在运行do_initcall函

    数时,会依次执行这些初始化函数,并且会在初始化结束后把这些函数所占用的内存释放掉。 回到mem.c文件,在最后有一行:

    __initcall(chr_dev_init)

    这句话的作用就显而易见了,在系统启动时自动执行chr_dev_init函数。所以我们完全可以不用在mem.c/chr_dev_init中添加我们

    自己的初始化函数,而是在我们自己的设备文件中(mydrv.c)添加如下一行: __initcall(mydrv_init).

    在我们前面说到的我们自己的设备文件mydrv.c中,最后有一句: module_init(mydrv _init);

    大家可以看一下module_init的定义,在…linux.-2.4.x\include\linux\init.h中。如果定义了宏MODULE

    时,module_init是作为模块初始化函数,如果没有定义MODULE,则

    module_init(fn)就被定义为__initcall(fn)。静态编译时是不定义MODULE的,所以我们的驱动中的module_init

    就等于是: __initcall(mydrv_init). 这样我们的初始化函数就会在启动时被执行了。

    至于究竟是在mem.c/chr_dev_init中添加你的设备初始化函数,还是在设备文件中通过module_init来完成,完全取决于你的喜好,

    没有任何差别。如果你的初始化函数只是注册一个设备(没有申请内存等操作),那即使你在两个地方都加上(等于初始化了两次)也没关系,不会出错(有兴趣可

    以看一下内核里注册设备的函数实现,

    …linux-2.4.x\fs\devices.c\register_chrdev)。不过为了规范起见,还是不建议这样作。

    最后一个问题。在静态加载驱动的时候,我们那个mydrv_cleanup和module_exit函数永远不会被执行,所以去掉是完全可以的,不过为了

    程序看起来结构清晰,也为了与动态加载的程序兼容,还是建议保留着。

    下面讲一下动态加载驱动的方法。1、运行make menuconfgi,在内核配置中进入Loadable module support,选择Enable loadable

    module support和Kernel module

    loader(NEW)两个选项。在应用程序配置中进入busybox,选择insmod, rmmod, lsmod三个选项。2、在…vendors\Samsung\2500\Makefile中添加相应的设备节点,方法与静态加载时完全一样。

    3、编写自己的驱动程序文件,在文件开始处加一句:

    #define MODULE

    文件最后的

    mydrv_init

    mydrv_cleanup module_init(mydrv _init)

    module_exit (mydrv _cleanup) 这四项必须保留。

    4、仿照如下的格式写自己的Makefile文件:KERNELDIR=

    /home/hexf/hardware/nHD/Design/firmware/uClinux-Samsung-2500/linux-2.4.x

    CFLAGS = -D__KERNEL__ -I$(KERNELDIR)/include \ -Wall

    -Wstrict-prototypes -Wno-trigraphs -O2 -fno-strict-aliasing -fno-common

    -fno-common -pipe -fno-builtin -D__linux__ -DNO_MM -mapcs-32

    -mshort-load-bytes -msoft-float

    CC = arm-elf-gcc

    all: mydrv.o

    clean: rm -f *.o

    5、编译自己的驱动程序文件。注意在动态加载时只编译不连接,所以得到的是.o文件。

    6、把编译后的驱动程序的.o

    文件,连同自己的测试程序(假设叫mytest,注意这个是可执行文件)一起放在编译服务器的/exports/自己的目录下。

    测试程序就是一个普通的应用程序,其编写和编译的步骤这里就不讲了。

    7、启动nHD板卡,用nfs的方法把编译服务器上/exports/自己的目录mount上来(假设mount 到

    /mnt下)。Nfs的使用大家都很熟悉了,这里就不再说。

    8、

    cd /mnt

    /bin/insmod mydrv.o

    现在你的设备就已经被动态加载到系统里了。可以用lsmod命令查看当前已挂接的模块。

    9、运行你的测试程序

    10、调试完毕后用 rmmod mydrv把你的设备卸载掉。 补充几点:

    1、关于建立设备节点的问题,因为大家所使用的系统不太一样,所以不需要按照我说的方法。总之只要在你自己的系统的dev目录下建立了自己的驱动程序的设

    备节点就可以了。

    2、没有考虑动态分配主设备号的问题。所以注册设备那个地方稍微有点不严密。

    3、模块加载时要把自己的.c文件编译成.o文件,CFLAGS后面那一串编译选项有时可能有点烦人,如果你没搞定,最简单的办法就是重新编译一遍内核并

    重定向到一个文件中(别忘了先make clean一下):make > out。

    然后在out文件里随便找一个字符驱动程序的编译过程,把它的编译选项找出来,拷贝到你自己的Makefile里就可以了。我就是这么作的。

    下面是一个最简单的字符设备驱动的例子。实际的驱动千差万别,但其实也就是

    “填充”自己的open,close,read,write,ioctl几个函数而已

    阅读(2078) | 评论(0) | 转发(0) |

    展开全文
  • Linux驱动静态加载和动态加载详解

    千次阅读 2016-08-08 20:06:09
    说明:这是我最近给单位写的一篇...在LINUX加载驱动程序可以采用动态和静态两种方式。静态加载就是把驱动程序直接编译到内核里,系统启动后可以直接调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重
  • 一、概念简述在Linux下可以通过两种方式加载驱动程序:静态加载和动态加载。静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译和...
  • 这些驱动程序源码可以修改到内核中,也可以把他们编译成模块形势,在需要的时候动态加载Linux内核是一个整体是结构,因此向内核添加任何东西,或者删除某些功能,都十分困难。为了解决这个问题引入了内核机制。  ...
  • linux下静态/动态加载驱动程序的方法说明:这是我最近给单位写的一篇文档,没有什么复杂的东东,对刚接触linuxdriver的朋友或许有点帮助。文档本来是针对我们自己的产品的,有些地方(路径、mknod、动态分配主设备号...
  • LINUX下加载驱动程序可以采用动态和静态...动态加载利用了LINUX的module特性,可以在系统启动后用insmod命令把驱动程序(.o文件)添加上去,在不需要的时候用rmmod命令来卸载。在台式机上一般采用动态加载的方式。在
  • linux驱动入门,编译,动态加载

    千次阅读 2017-09-15 11:19:31
    直接编译进内核就是这个模块和内核一起编译,如果有什么这个驱动有什么问题的话,我们还需要调试编译整个内核,因此刚开始学习的时候我采用了模块化的动态加载内核。一、动态加入内核#include <linux/ini
  • 这些驱动程序源码可以修改到内核中,也可以把他们编译成模块形势,在需要的时候动态加载Linux内核是一个整体是结构,因此向内核添加任何东西,或者删除某些功能,都十分困难。为了解决这个问题引入了内核机制。  ...
  • linux动态加载程序

    2013-05-04 19:49:00
    应用情况:在PC,linux下编译好.KO模块驱动,移植到TQ244O上运行。 模块加载的几个命令:insmod ,modprobe,rmmod ,lsmod ,mkmod。 #insmod *.ko //在*.ko所在目录下运行此命令,将模块加载到系统中。 #...
  • 驱动程序加载方式

    2020-12-21 09:31:08
    Linux设备驱动程序有两种加载方式。一种是直接编译进Linux内核,在Linux启动时 加载;另一种是釆用内核模块方式,这种模块可动态加载与卸载。 如果希望将新驱动程序编译进内核,需要修改内核代码和编译选项。下面以...
  • LINUX加载驱动程序能够采用动态和静态两种方式。静态加载就是把驱动程序直接编译到内核里,系统启动后能够直接调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要从新编译下...
  • Linux 的众多优良特性之一就是可以在运行时扩展由内核提供的特性的能力. 这意味着你可以在系统正在... 每个模块由目标代码组成( 没有连接成一个完整可执行文件 ), 可以动态连接到运行中的内核中, 通过 insmod 程序, ...
  • Linux驱动程序模块编译流程

    千次阅读 2016-08-14 17:13:06
    Linux驱动程序可以在内核配置时直接编译进内核或者以模块编译成生.ko文件动态加载。 下面是arm开发板上驱动程序模块编译,动态加载的流程。 ##1.编写驱动程序源程序结合具体硬件编写。##2.修改内核配置文件##3. ...
  • 动态加载 在系统启动后,通过insmod或modprobe命令加载.ko内核目标文件,成功后可通过mknod指令进行挂载节点,不需要的时候可通过rmmod命令来卸载模块。 优点:容易控制内核的大小;使用灵活。 缺点:每次使用都需要...
  • android_dev,这个就是我们虚拟的硬件设备了,val成员变量就代表设备里面的寄存器,它的类型为int,sem成员变量是一个信号量,是用同步访问寄存器val的,dev成员变量是一个内嵌的字符设备,这个Linux驱动程序自定义...
  • 动态加载:多数的Linux设备驱动程序可以在核心模块发出加载请求时进行加载,同时在不使用设备时进行卸载,这样核心可以有效地利用系统的资源; ⑸可配置:Linux设备驱动属于核心的一部分,用户可以根据自己的...
  • LINUX下加载驱动程序可以采用动态...动态加载利用了LINUX的module特性,可以在系统启动后用insmod命令把驱动程序(.o文件)添加上去,在不需要的时候用rmmod命令来卸载。在台式机上一般采用动态加载的方式。 在嵌入
  • linux驱动程序安装

    2013-11-12 21:32:14
    linux下的驱动程序安装有模块方式与直接编译进内核。 1.模块方式 linux内核包含的组件很多,把所有的组件都编译进内核文件(zImage或者bzImage)会导致内核过大。使用内核模块可以让内核文件(zImage或者bzImage)...
  • 给出了在LINUX加载驱动程序的步骤和代码,包括动态和静态两种方式
  • linux驱动程序注册

    2018-12-17 15:13:24
    (4)module加载函数。 (5)module卸载函数。 (6)module许可声明(必须) (7)模块参数 (8)模块依赖 (9)模块作者等信息声明 一个linux内核模块主要由如下几个部分组成: 初始化  1、动态申请设备...
  • 模块参数很多情况下,我们期望通过...为了满足这种需求,内核允许对驱动程序指定参数,而这些参数可在加载驱动的过程中动态的改变参数的来源主要有两个 使用insmod/modprobe ./xxx.ko时候在命令行后直接给出参数; mod
  • 实验题目:嵌入式linux驱动程序设计

    千次阅读 2011-06-07 22:51:00
    实验题目:嵌入式linux驱动程序设计 实验目的:1.编写一个字符设备驱动2.掌握添加设备驱动程序的方法3.编写一个应用程序测试添加的驱动 实验步骤:1.在linux环境下编写字符驱动程序和测试驱动的应用程序2....
  • Linux驱动程序的概念、驱动结构、对中断和内存的处理、设备驱动的初始化 Linux下设备驱动程序开发框架和流程 Linux下模块化驱动程序设计(动态加载) 设备驱动加入Linux内核中 实验:编写驱动程序框架+测试用例...
  • (1)此类载入的模块,通常为设备驱动程序。设备驱动里面会使用到内核驱动,比如使用交叉编译或官网下载的一个在linux系统下工作的设备驱动,因为是针对linux系统而制作的,它知道内核支持的基本驱动,比如I2C、SPI...
  • Linux内核驱动加载过程 驱动加载分为两种情况:静态加载和动态...静态加载的方法是把驱动程序直接编译进内核,然后内核在启动过程中由do_initcall()函数加载。 do_initcalls()函数路径在/init/main.c 过程如
  • Linux驱动的两种加载方式过程分析

    千次阅读 2018-10-22 10:18:24
    Linux下可以通过两种方式加载驱动程序:静态加载和动态加载。 静态加载就是把驱动程序直接编译进内核,系统启动后可以直接调用。静态加载的缺点是调试起来比较麻烦,每次修改一个地方都要重新编译和下载内核,...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 515
精华内容 206
关键字:

linux驱动程序动态加载

linux 订阅