8716|15

2131

帖子

0

TA的资源

至上芯片

楼主
 

请教linux驱动开发过程 [复制链接]

大家写过linux驱动程序吗?可以给大家讲一下过程吗?

[ 本帖最后由 daicheng 于 2009-6-16 14:17 编辑 ]

如何编写Linux设备驱动程序.rar

23.84 KB, 下载次数: 339

最新回复

支持!  详情 回复 发表于 2010-2-2 14:24
点赞 关注
个人签名处处留心皆学问!

回复
举报

2131

帖子

0

TA的资源

至上芯片

沙发
 
如:设备文件 的操作
1 系统加载驱动
2 应用程序里打开设备(文件)
3 应用程序对设备操作
4 应用程序关闭设备(文件)
5 系统关闭设备
没人讨论一下啊?
 
个人签名处处留心皆学问!
 

回复

633

帖子

0

TA的资源

裸片初长成(中级)

板凳
 

以s3c2410为例,UART驱动流程

转载的,觉得不错~~

初始化

1 定义一个uart_driver的变量并初始化好(无需提供tty_driver).

2  uart_register_driver()来注册这个驱动,在这函数里它会分配一个tty_driver对象,并初始化tty_operations为uart_ops, 这是serial-core.c提供的统一的UART操作函数

3 调用自己定义的一个init函数来注册一个platform_driver对象, 这样可以让系统调用我们的probe函数和disconn函数等. 在这些函数里我们可以做一些硬件方面的初始化和卸载操作.

4  probe():  这里我们先初始化硬件,接着调用uart_add_one_port()添加一个UART设备,(这里事先要定义一个uart_port对象,我们一般把这个对象内嵌在我们自己的结构里面, 并设好port的ops函数表)

操作

1 用户同过在设备文件上调用open,close,write等系统调用来操作我们的设备,以write为例,它会接着调用uart_write()(在注册驱动时设置的).

2  uart_write()会接着调用port->ops->start_tx()即我们port上的操作函数接口.

来源:http://blog.csdn.net/aaronychen/archive/2008/02/19/2106901.aspx

[ 本帖最后由 clark 于 2009-6-16 15:52 编辑 ]
 
 
 

回复

290

帖子

152

TA的资源

五彩晶圆(初级)

4
 
个人觉得需要先对Linux设备驱动了解一下,明白整个Linux 驱动的工作原理,也就是《Linux设备驱动》第三版,2.6内核的。
 
 
 

回复

290

帖子

152

TA的资源

五彩晶圆(初级)

5
 

Linux 2.6内核的编译步骤及模块的动态加载

Godbach 的博客(http://blog.chinaunix.net/u/33048/showart_343553.html)可以作为参考:

05年本科毕业设计做的是Linux下驱动的剖析,当时就买了一本《Linux设备驱动程序(第二版)》,但是没有实现将最简单的helloworld程序编译成模块,加载到kernel里。不过,现在自己确实打算做一款芯片的Linux的驱动,因此,又开始看了《Linux设备驱动程序》这本书,不过已经是第三版了。第二版讲的是2.4的内核,第三版讲的是2.6 的内核。两个内核版本之间关于编译内核以及加载模块的方法都有所变化。

本文是基于2.6的内核,也建议各位可以先看一下《Linux内核设计与实现(第二版)》作为一个基础知识的铺垫。当然,从实践角度来看,只要按着以下的步骤去做也应该可以实现成功编译内核及加载模块。

个人用的Linux版本为:Debian GNU/Linux,内核版本为:2.6.20-1-686.

(1)第一步,下载Linux内核的源代码,即构建LDD3(Linux Device Drivers 3rd)上面所说的内核树。
如果安装的Linux系统中已经自带了源代码的话,应该在/usr/src目录下。如果该目录为空的话,则需要自己手动下载源代码。下载代码的方法和链接很多,也可以在CU上下载。不过,下载的内核版本最好和所运行的Linux系统的内核版本一致。当然,也可以比Linux系统内核的版本低,但高的话应该不行(个人尚未实践)。
Debian下可以很方便的通过Debian源下载:
首先查找一下可下载的内核源代码:
# apt-cache search linux-source
其中显示的有:linux-source-2.6.20,没有和我的内核版本完全匹配,不过也没关系,直接下载就可以了:
# apt-get install linux-source-2.6.20
下载完成后,安装在/usr/src下,文件名为:linux-source-2.6.20.tar.bz2,是一个压缩包,解压缩既可以得到整个内核的源代码:
# tar jxvf linux-source-2.6.20.tar.bz2
解压后生成一个新的目录/usr/src/linux--source-2.6.20,所有的源代码都在该目录下。
注:该目录会因内核版本的不同而不同,各位动手实践的朋友只需知道自己的源代码所在的具体位置即可。

(2)第二步:配置及编译内核。
进入/usr/src/linux--source-2.6.20目录下,可以看到Makefile文件,它包含了整个内核树编译信息。该文件最上面四行是关于内核版本的信息。对于整个Makefile可以不用做修改,采用默认的就可以了。
一般情况下,需要先用命令诸如"make menuconfig", "make xconfig"或者"make oldcofig"对内核进行配置,这几个都是对内核进行配置的命令,只是它们运行的环境不一样,执行一下这几个命令中的任何一个即可对内核进行配置:
make menuconfig是基于界面的内核配置方法,make xconfig应该是基于QT库的,还有make gcofig也是基于图形的配置方法,应该是需要GTK的环境,make oldcofig就是对内核树原有的.config文件进行配置一下即可。
其实内核的配置部分,主要是保证内核启动模块可动态加载的配置,默认配置里面应该已经包含了这样的内容,因此,我用的是make oldconfig.

在内核源码的目录下执行的所有步骤如下:
# make mrproper
# make xconfig (make menuconfig, make oldconfig)
# make (2.4下可能要执行# make bzImage,但2.6下面就不用了)

这个过程可能要持续一个小时左右,因此是对整个内核重新编译了。执行结束后,可以看到在当前目录下生成了一个新的文件: vmlinux, 其属性为-rwxr-xr-x。
然后执行:
# make modules
# make modules_install
对内核的所有模块进行编译和安装。其中make modules也可以不用执行,直接make modules_install就可以了,因为执行make时已经包含了生成内核模块的动作。

执行结束之后,会在/lib/modules下生成新的目录/lib/modules/2.6.20/。 在随后的编译模块文件时,要用到这个路径下的build目录。

(3)引导新编译的内核
对整个内核编译完成后,就需要让系统可以启动新编译的内核。在2.4版本中,如果需要引导新编译的内核,则要通过以下四个步骤:
a. 拷贝内核镜像至boot下
# cp kernel_dir/arch/i386/boot/bzImage /boot/vmlinuz-kernel-version

b.拷贝System.map至/boot下
# cp System.map /boot/System.map-kernel-version


c. 在boot下生成内核的img文件
# /sbin/mkinitrd initrd-kernel-version.img

d.修改引导文件grub.conf或者lilo.conf,添加新内核的启动项。

而在2.6内核下,实现以上四个步骤只用一个简单的命令即可实现:
内核目录下执行:
# make install

如果没有添加引导菜单的话,就手工添加即可。

至此,内核编译完成。可以重启一下系统。

内核的详细配置请见另外一位网友的帖子,这里给出链接:
http://linux.chinaunix.net/bbs/viewthread.php?tid=885597&extra=page%3D1%26amp%3Bfilter%3Ddigest

第三步:编写模块文件及Makefile
以LDD3上的hello.c为例:
//hello.c
#include
#include
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_ALERT "Hello, world\n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT"Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

Makefile文件的内容为:

obj-m := hello.o
KERNELDIR := /lib/modules/2.6.20/build
PWD := $(shell pwd)

modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

其中,hello.c和Makefile文件应该位于同一个目录下,可以放在/home下,我的两个文件都位于/home/david/.

第四步:编译和装载模块

在文件所处的目录下,执行:
debian:/home/david # make

然后查看该目录下有哪些文件生成:
debian:/home/david # ls -l
总计 28
drwxr-xr-x 2 david david 4096 2007-02-07 17:49 Desktop
-rw-r--r-- 1 david david  462 2007-07-20 13:42 hello.c
-rw-r--r-- 1 root  root  2432 2007-07-20 13:55 hello.ko
-rw-r--r-- 1 root  root   607 2007-07-20 13:55 hello.mod.c
-rw-r--r-- 1 root  root  1968 2007-07-20 13:55 hello.mod.o
-rw-r--r-- 1 root  root  1140 2007-07-20 13:55 hello.o
-rw-r--r-- 1 david david  267 2007-07-20 13:48 Makefile
-rw-r--r-- 1 root  root     0 2007-07-05 14:11 Module.symvers

可见,已经生成模块文件hello.ko.
然后,就可以加载该模块:
debian:/home/david # insmod hello.ko

查看模块是否加载进内核:
debian:/home/david # lsmod
Module                  Size  Used by
hello                   1344  0
nfs                   219468  0
nfsd                  202224  17
...                 ...

其中Module名为hello的即为我们所加载的模块.

卸载模块:

debian:/home/david # rmmod hello

同样可以通过lsmod来查看该模块是否被卸载.

这里有两个问题,其一就是printk()输出的问题.LDD3上也说,在加载和卸载模块的时候都会有信息输出在屏幕上,如果在Windows下通过终端仿真器(我们常用的虚拟机算是一种),则在屏幕上看不到任何输出.我同时在虚拟机和和物理机都运行了该模块,均未看到有"Hello, world"(加载模块时printk的输出)或"Goodby, cruel world"(卸载模块时printk的输出). 这个不知道是我操作系统发行版的原因还是系统配置的问题,请了解这个问题的朋友指点一下.

其二,书上讲到如果屏幕上看不到信息,可能输出在某个日志文件里面了,并说可能在/var/log/messages文件中.并且看到网上很多网友也说是输出到这个文件里面.我不知道有没有发现输出在其他日志文件里的,不过我的这个信息输出在/var/log/syslog里面.在加载和卸载完该模块后, 执行命令:
debian:/home/david # cat /var/log/syslog | grep world
可以看到有两行内容.当然,也可以不用grep world, 应该会出现在最后两行.

Jul 20 14:15:29 localhost kernel: Hello, world
Jul 20 14:15:34 localhost kernel: Goodbye, cruel world

这就是printk应该输出的信息.

这里有另外一个方法,可以实现printk的信息输出在屏幕上,即更改printk输出的优先级.例子中的优先级为:KERN_ALERT,优先级为<1>,如果将优先级改为KERN_EMERG即<0>,则可以看到屏幕的输出信息.
修改的方法只是修改一下hello.c中两句printk()的内容,修改后的hello.c如下:

#include
#include
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_EMERG "Hello, world\n");  /*改动部分*/
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_EMERG"Goodbye, cruel world\n"); /*改动部分*/
}

module_init(hello_init);
module_exit(hello_exit);

同样的方法编译生成模块,再次用insmod和rmmod,则在屏幕上看到的输出信息为:

debian:/home/david# insmod hello.ko
debian:/home/david#
Message from syslogd@localhost at Fri Jul 20 14:27:32 2007 ...
localhost kernel: Hello, world

debian:/home/david# rmmod hello
debian:/home/david#
Message from syslogd@localhost at Fri Jul 20 14:27:42 2007 ...
localhost kernel: Goodbye, cruel world

debian:/home/david
但是,是否能够将printk()的优先级改为KERN_EMERG值得商榷.因为在Linux Kernel Development中,对该优先级的描述为: An emergency condition; the system is probably dead.

以上就是整个2.6内核编译步骤以及模块动态加载的方法.理解和解释有误的地方,也请各位浏览本文的朋友指点,也希望能和对内核和驱动感兴趣的朋友交流.

本文也参考了一位网友博客上一篇关于编译2.6内核的文章,这里给出链接:
http://blog.csdn.net/wooin/archive/2007/05/21/1619141.aspx

【08-10】补充:本文最后所提到的模块加载和卸载时没有看到屏幕的输出信息,即printk输出的问题。经过实践之后,本人发现了个人的原因,和大家交流一下。LDD3书中所说的看不到输出指的是在终端仿真器,就是我们平时在X-Window下用的终端,譬如我用的时Gnome-Terminal,在这种情况下看不到屏幕的输出。而我上面的例程正是在终端下运行的。当时没想到切换到控制台Console运行一下试试。今天在控制台运行了,发现无论是在虚拟机还是物理机下,只要在Console下面运行,是可以看到屏幕输出的。








 
 
 

回复

2771

帖子

0

TA的资源

裸片初长成(中级)

6
 

顶,很好哦,LS加油
 
 
 

回复

285

帖子

3723

TA的资源

五彩晶圆(中级)

7
 
设备驱动程序的开发过程 由于嵌入式设备由于硬件种类非常丰富,在默认的内核发布版中不一定包括所有驱动程序。所以进行嵌入式Linux系统的开发,很大的工作量是为各种设备编写驱动程序。除非系统不使用操作系统,程序直接操纵硬件。嵌入式Linux系统驱动程序开发与普通Linux开发没有区别。可以在硬件生产厂家或者Internet上寻找驱动程序,也可以根据相近的硬件驱动程序来改写,这样可以加快开发速度。实现一个嵌入式Linux设备驱动的大致流程如下。

(1)查看原理图,理解设备的工作原理。一般嵌入式处理器的生产商提供参考电路,也可以根据需要自行设计。

(2)定义设备号。设备由一个主设备号和一个次设备号来标识。主设备号惟一标识了设备类型,即设备驱动程序类型,它是块设备表或字符设备表中设备表项的索引。次设备号仅由设备驱动程序解释,区分被一个设备驱动控制下的某个独立的设备。

(3)实现初始化函数。在驱动程序中实现驱动的注册和卸载。

(4)设计所要实现的文件操作,定义file_operations结构。

(5)实现所需的文件操作调用,如read、write等。

(6)实现中断服务,并用request_irq向内核注册,中断并不是每个设备驱动所必需的。

(7)编译该驱动程序到内核中,或者用insmod命令加载模块。

(8)测试该设备,编写应用程序,对驱动程序进行测试。
 
 
 

回复

565

帖子

513

TA的资源

裸片初长成(中级)

8
 

回复 楼主 daicheng 的帖子

问题有些大哦,楼主可否缩小下范围再讨论?
 
 
 

回复

440

帖子

0

TA的资源

五彩晶圆(高级)

9
 
最近刚花了大把银子买了传说中经典的《Linux设备驱动 第三版》,感觉一下子被吸引进去了。不过因为基础不是很全面,里面的东西开展得很快,有好些地方不是很明了,也找不到个明白的人问。唉,进度有些慢。。。
 
 
 

回复

2131

帖子

0

TA的资源

至上芯片

10
 
呵呵!讲的太好了,学习了!
 
个人签名处处留心皆学问!
 
 

回复

2万

帖子

74

TA的资源

管理员

11
 

回复 9楼 Michael_Fei 的帖子

版主,要不咱们组织个活动就研读Linux设备驱动 第三版 大家讨论着,是不是效果会更好呢?
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

440

帖子

0

TA的资源

五彩晶圆(高级)

12
 
支持楼上,正看着这本书,很经典的说。不过理解起来也是费劲啊,请教大家了。
 
 
 

回复

182

帖子

0

TA的资源

纯净的硅(高级)

13
 
谢谢分享!自己实践一下!
 
个人签名基础决定高度!
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

14
 
正在学习中
 
 
 

回复

35

帖子

0

TA的资源

一粒金砂(初级)

15
 
很强大很好的资料谢谢楼主提供
 
 
 

回复

1668

帖子

0

TA的资源

裸片初长成(初级)

16
 

回复 11楼 soso 的帖子

支持!
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表