在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

#include

#include

#include

#include // printk()

#include // kmalloc()

#include // error codes

#include // size_t

#include // mark_bh

#include

#include

#include

#include

#include

#include

#include

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);

在linux添加驱动程序,linux下静态/动态加载驱动的两种方式相关推荐

  1. vue.js 动态加载 html,Vue加载组件、动态加载组件的几种方式

    什么是组件: 组件是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能.在有些情况下,组件也可以是原生HT ...

  2. Vue动态加载组件的四种方式

    动态加载组件的四种方式: 1.使用import导入组件,可以获取到组件 var name = 'system'; var myComponent =() => import('../compon ...

  3. Java反射-静态/动态加载类

    title: Java反射-静态/动态加载类 date: 2019-05-28 18:50:00Java反射-静态/动态加载类 Class 类是对象,是java.lang.Class类的实例对象.任何 ...

  4. (一)JQuery动态加载js的三种方法

    Jquery动态加载js的三种方法如下: 第一种: $.getscript("test.js"); 例如: <script type="text/javascrip ...

  5. 动态加载html 添加样式表,使页面动态加载不同CSS样式表,从而实现不同风格模板的方法...

    我们在制作网页时,有时会制作多种风格模板,而想把这些模板都用起来,而又不知道方法,通过以下两种方法,你就可以实现相同网站不同CSS模板的方法. ASP.Net中利用CSS实现多界面两种方法. 方法一: ...

  6. C#动态调用WCF接口,两种方式任你选。

    REFERENCE FROM : http://www.cnblogs.com/Leo_wl/p/4762784.html 写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触 ...

  7. 2019-8-19 [Linux] 3.为什么要修改静态IP IP的获取有几种方式 设置静态IP后无法Ping百度怎么办 可以ping后CRT无法连接怎么办

    文章目录 3.修改linux系统的静态IP 问题1 : 为什么要修改静态IP? 问题2 : IP的获取有几种方式? 手动或者自动 验证是否可以正常上网 ping一下百度 看一下是否可以正常上网 问题3 ...

  8. Vue踩坑之二级路由下静态资源加载失败

    在使用vue开发过程中意外发现 , 当我的路由加到二级时我的页面背景突然没了? 这是怎么回事呢? 让我们先来复现一下问题吧 起初我的登陆页面的路由是这样子的 我的背景图片是在外部的一个css中写着的 ...

  9. orangepi3 lts动态加载驱动

    orangepi3 lts驱动编译 源码下载 按照手册指示从github下载或直接从百度网盘下载 git clone https://github.com/orangepi-xunlong/orang ...

  10. Linux系统-安装显卡GPU驱动的两种方式

    方案1 1)先到NVIDIA的官方下载 xx.run GPU驱动文件,可以到官方下载对应的版本: https://www.nvidia.cn/Download/Find.aspx?lang=cn ub ...

最新文章

  1. 转入肥胖基因改造RNA,作物增产50%
  2. python创建一个字典、关键字为只包含字母的字符串_探究Python源码,终于弄懂了字符串驻留技术...
  3. maven多profile环境打包下-P参数和-D参数
  4. hdu 1042 N!(大数)
  5. UImenuController
  6. 计算机报名显示事务已被锁死,ORA-01591错误处理: 锁定已被有问题的分配事务处理20.18.156406挂起(转载)...
  7. leetcode1050. 合作过至少三次的演员和导演(SQL)
  8. 计算机网络(五)——组建客户机/服务器网络
  9. 2699元!魅族16s Pro现货售罄:将加紧备货
  10. 小学生也能看懂的ArrayList底层原理
  11. 【OCR一】字符识别技术总览(转)
  12. 模仿QQ带侧边栏框架搭建
  13. 开源巨献:Google最热门60款开源项目
  14. 【C++】内存4区---代码区、全局区、栈区、堆区
  15. pytest框架(三)
  16. 帆软认证报表工程师FCRA试题
  17. 数字图像算术编码python_算术编码的python实现
  18. 我国计算机科学与技术发展历史,计算机科学与技术的发展趋势探析
  19. 计算机程序设计艺术读书感悟
  20. aptana安装python库_使用Aptana搭建Python开发环境

热门文章

  1. QT第三方串口类Win_QextSerialPort,串口工具插拔后无法继续使用问题
  2. C语言程序设计课题分析,C语言程序设计综合实践性教学课题报告.doc
  3. 微信分享链接php,微信实现分享链接的缩略图和标题
  4. (一)查询出排序中的最大值和最小值
  5. 嵌入式开发之GCC编译器使用
  6. win7设置固定IP重启后无法上网,ipconfig显示为自动配置IPV4 169.254的地址
  7. 重装windows后ubuntu系统启动菜单不见的修复方法
  8. IOS错误---“A valid provisioning profile for this executable was not found”
  9. 以德服人——合格的产品经理
  10. 基于C#的Access MsSQL MySQL 三种数据库访问演示(含源文件Demo)