`
peizhiinfo
  • 浏览: 1426590 次
文章分类
社区版块
存档分类
最新评论

Linux字符设备驱动(一)

 
阅读更多

Linux字符设备驱动之概述篇

.概述:

1.Linux中有一句哲学“Linux下皆文件”。

设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。

但是设备文件和普通文件还是又差别的。

那么设备和普通文件之间又有什么区分呢?

先看看两个图:

普通文件:

-rw-r--r-- 1 stella stella 3699 2011-05-10 16:02 my_USBTMCAPP.c

-rwxr-xr-x 1 stella stella 8763 2011-05-08 11:27 tiger

-rw-r--r-- 1 stella stella 441 2011-05-08 11:27 tiger.c

设备文件:

crw------- 1 root root 252, 4 2011-05-11 16:42 usbmon4

crw------- 1 root root 252, 5 2011-05-11 16:42 usbmon5

crw-rw---- 1 root tty 7, 0 2011-05-11 16:42 vcs

crw-rw---- 1 root tty 7, 1 2011-05-11 16:42 vcs1

1>访问权限之前的字母是bc,分别表示块设备和字符设备。

2>设备文件没有文件长度,而增加了另外的两个值,分别是主设备号和从设备号。二者共同形成一个唯一的号码,内核可由此查找对应的设备驱动程序。

3>之所以给设备文件分配名称,是因为用户更容易记忆符号名而不是数字,但名称无法表示设备文件的实际功能,这主要是通过主从设备号表示一个设备的,设备文件所处的目录也与其功能不相干。

尽管如此,命名设备文件时仍然采用了一中标准方法:

mknod 用于创建设备文件

2.内核采用主从设备号来标识匹配的驱动程序

为什么要采用两个号码来标识驱动程序呢?

1>首先,系统可能包含几个同样类型的设备,由同一个设备驱动程序管理(将同样的代码多次加载到内核也没有意义)

2>其次,可以将同类设备合并起来,便于插入到内核的数据结构中进行管理

3.Linux设备驱动程序的分类:

1>Linux设备驱动程序分为字符设备驱动(无缓冲且只能顺序存取),块设备驱动程序(有缓冲且可以随机存取)。每个字符设备和块设备都必须有主次设备号主设备号相同的设备是同类设备(使用同一驱动程序)

(1)块设备:系统中能够随机(不需要按顺序)访问固定大小数据片(chunk)的设备被称作块设备;他们都是以安装文件系统的方式使用的

(2)字符设备:字符设备按照字符流动的方式被有序访问

2>这些设备中,有些设备是对实际物理硬件的抽象,而有些设备则是内核自身提供的功能(不依赖于特定的物理硬件,又称为“虚拟设备”)

(1)每个设备在/dev目录下都有一个对应的文件(节点)

可以用下面的命令进行查看

cd /dev

ls -al

日期的前两列给出了对应设备的主设备号和次设备号

(2)可以通过cat /proc/devices命令查看当前已经加载的设备驱动程序的主设备号,第一列为主设备号,第二列为设备名

3>块设备和字符设备的主设备号可能是相同的。因此,除非同时指定设备号和设备类型(块设备/字符设备),否则找到的驱动程序可能不是唯一的

4.主从设备号

1>在内核中,dev_t类型用来保存设备编号(包括主设备号和次设备号),dev_t是一个32位的数,12位表示主设备号,20为表示次设备号

(1)主设备号 = MAJORdev_t dev

(2)次设备号 = MINORdev_t dev

(3)设备编号 = MKDEVint major,int minor

2>主设备号是与驱动对应的概念,同一类设备一般使用相同的主设备号,不同类的设备一般使用不同的主设备号。因为同一驱动可支持多个同类设备,因此用次设备号来描述使用该驱动的设备的序号,序号一般从0开始

5.MKDEV()宏的实现

#define MKDEV(ma,mi) (((ma) << MINORBITS)|(mi))

#define MKDEV(ma,mi) ((ma)<<8 | (mi))

获取设备在设备表中的位置

6.dev_t是无符号长整型号

1>typedef u_long dev_t;

2>typeddef unsigned long u_long;

7.分配和释放设备号:

(1)int register_chrdev_region(dev_t first,unsigned int count,char *name);

(2)int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);

(3)void unregister_chrdev_region(dev_t first,unsigned int count);

1>register_chardev_region函数用于已知起始设备号的情况;在静态申请时,如果主设备号没有和系统中某个字符设备的主设备号 重复,则此函数肯定会成功返回;如果系统中某个已注册的字符设备的主设备号与申请的主设备号相同,则内核还需要检查这两个设备的次设备号范围有没有重合,若有重合部分,则register_chrdev_region返回-EBUSY,表示系统正忙,申请的设备号已被占用;若无重合部分,则register_chrdev_region返回0,表示成功

2>alloc_chrdev_region()用于设备号未知,向系统动态申请设备号的情况。动态分配设备号,是指在驱动程序中通过调用此函数,系统将为驱动程序动态分配一个主设备号,将分配到的主设备号与参数baseminor组合成一个设备号,通过输出参数dev返回给用户

3>alloc_chrdev_region()register_chrdev_region()对比的优点在于它会自动避开设备号重复的冲突,但是当用alloc_chrdev_region动态申请设备号时,在申请完后,要通过major=MMOR(dev)获取主设备号;并且如果用户使用静态申请设备号,只要用户申请的主设备号在0~2^12-1之间,次设备号在0~2^20-1之间,并且设备号不冲突,内核就会成功注册该设备号;而如果用户使用了动态分配设备号,内核为用户分配的主设备号只会在1~254之间,如果这254个设备号全部被占用,则动态分配设备号会失败,但是常用的设备只有三十多个,所以基本上不用担心动态分配的时候内核会返回失败

4>在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号

-----------------------------------------------------------------------------------------

关于register_chrdev_region()函数系列的具体实现可以参看《Linux字符设备驱动之register_chrdev_region

-----------------------------------------------------------------------------------------

8. 注册字符设备

在获得了设备号范围之后,需要将设备添加到字符设备数据库中,以激活设备。这需要用cdev_init函数初始化一个struct cdev的实例,然后调用cdev_add函数

(1)void cdev_init(struct cdev *cdev,struct file_operation *fops);

(2)int cdev_add(struct cdev *dev,dev_t num,unsigned int count)

(3)void cdev_del(stuct cdev *dev)

1> cdev_init()函数用于初始化cdev的成员,并建立cdevfile_operations之间的连接

2>cdev_add()函数和cdev_del()函数分别向系统添加和删除一个cdev,完成字符设备的注册和注销。对cdev_add()的调用通常发生在字符设备驱动模块加载函数中,而对cdev_del()函数的调用则通常发生在字符设备驱动模块卸载函数中。

3>先要申请设备号,才能注册字符设备,顺序不能乱

-----------------------------------------------------------------------------------------

关于cdev_init ()函数系列的具体实现可以参看《Linux字符设备驱动之cdev_init ()

-----------------------------------------------------------------------------------------

9.在内核空间和用户空间之间拷贝数据使用

(1)unsigned long copy_to_user(void _user* to,const void *from,unsigned long count);

(2)unsigned long copy_from_user(void *to,const void __user *from,unsigned long count);

由于内核空间与用户空间的内存不能直接互访问,因此借助函数copy_from_user()完成用户空间到内核空间的复制。函数copy_to_user()完成内核空间到用户空间的复制

分享到:
评论

相关推荐

    linux字符设备驱动实例

    本例子是一个linux字符设备驱动的最简单的例子,有详细的说明,适合初次接触者。

    Linux字符设备驱动总结

    linux 字符设备驱动 字符设备是指在I/O传输过程中以字符为单位进行传输的设备,例如键盘,打印机等。请注意,以字符为单位并不一定意味着是以字节为单位,因为有的编码规则规定,1个字符占16比特,合2个字节。  在...

    Linux字符设备驱动实现

    编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序。可以有一个读,一个写进程共享该字符设备,进行聊天;也可以由多个读和多个写进程共享该字符设备,进行聊天

    嵌入式Linux字符设备驱动的设计与应用

    嵌入式Linux字符设备驱动的设计与应用 嵌入式Linux字符设备驱动的设计与应用

    Linux下支持阻塞操作的字符设备驱动

    Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动Linux下支持阻塞操作的字符设备驱动...

    深入浅出 Linux字符设备驱动程序解析

    深入浅出 Linux字符设备驱动程序解析

    Linux字符设备驱动实验代码

    简单的字符设备的驱动程序,并对所编写的设备驱动程序进行测试,了解Linux操作系统如何管理字符设备。由于网上许多资源不完整,本资源整合了许多内容。包括驱动程序memdev.c,memdev.h,app-mem.c,MakeFile文件。...

    基于Linux字符设备驱动程序的设计与实现

    Linux 设备驱动程序是为特定的硬件提供给用户程序的 一组标准化接口,它隐藏了设备工作的细节。Linux 系统下 驱动程序是运行在内核态的,是和...Linux 系统的设备分为3 种类型,分别是字符设备、 块设备和网络设备。

    linux字符设备驱动模型

    linux字符设备驱动模型

    linux字符设备驱动程序学习笔记

    详细介绍了linux字符设备驱动程序,对各个名词做了自己的理解,在学习中的笔记,有错误还请海涵

    Linux 字符设备驱动程序的设计

    介绍了Linux 字符设备驱动程序中建立设备,初始化设备、设备的资源分配和如 何访问设备的方法及相关函数的实现.

    Linux字符设备驱动(转载)

    概括的说,字符设备驱动主要要做三件事:1、定义一个结构体static struct file_operations变量,其内定义一些设备的打开、关闭、读、写、控制函数;2、在结构体外分别实现结构体中定义的这些函数;3、向内核中注册或...

    最简单的linux字符设备驱动

    一个最简单的字符设备驱动程序,包括LDD第三版前三章的内容。 关键是书中并未讲的太细,关于mknod以及如何自己写一个程序使用自己的驱动,我的代码中有详细的过程,也在blog中写明了驱动模块的思路以及常见问题的...

    嵌入式Linux下字符型设备驱动程序的开发

    嵌入式Linux下字符型设备驱动程序的开发,驱动开发入门首选~

    linux字符设备驱动

    1)编写一个简单的字符设备驱动程序,该字符设备包括打开、读、写、I/O控制与释放五个基本操作。 2)编写一个测试程序,测试字符设备驱动程序的正确性。 3)要求在实验报告中列出Linux内核的版本与内核加载的过程

    Linux增加字符设备驱动实验

    Linux增加字符设备驱动实验,可以打印出一个hello world

    Linux字符设备驱动架构分析

    Linux字符设备驱动架构分析,Linux字符设备驱动架构分析,Linux字符设备驱动架构分析

    linux字符设备驱动程序

    “mydriver”的简单字符设备驱动程序,该驱动程序以可加载的模块方式进行编译,这样可以免去重新编译内核的工作。

    linux 字符设备驱动程序 示例代码

    linux字符设备驱动程序,示例代码。 共8个文件。包括内核态的驱动程序和用户态的测试例程。

Global site tag (gtag.js) - Google Analytics