linux设备驱动--字符设备模型
最近正在学习设备驱动开发,因此打算写一个系列博客,即是对自己学习的一个总结,也是对自己的一个督促,有不对,不足,需要改正的地方还望大家指出,而且希望结识志同道合的朋友一起学习技术,共同进步。
作者:liufei_learning(转载请注明出处)
email:flying0216@foxmail.com
IT学习交流群:160855096
开发环境:Win7(主机)+ VisualBox + ubuntu10.10(虚拟机) + TQ2440开发板(2.6.30.4内核)
功能: 1.接linux设备驱动--LED驱动
用cdev实现led驱动的编写
2.学习字符设备模型(转载)
目录:1.cdev实现led驱动的编写
1)实现及源码
2)cdev结构分析
2.学习字符设备模型
1)字符设备模型
2)字符设备的设备号
3)文件系统中对字符设备文件的访问
用cdev实现led驱动的编写
在上一节代码基础上修改的,详细看linux设备驱动--LED驱动
分析:
Linux/cdev.h
在Linux内核中使用cdev结构体描述字符设备。该结构体是所有字符设备的抽象,其包含了大量字符设备所共有的特性。cdev结构体定义如下:
cdev结构中的kobj结构用于内核管理字符设备,驱动开发人员一般不使用该成员。ops是指向file_operations结构的指针,该结构定义了操作字符设备的函数。dev就是用来存储字符设备所申请的设备号。count表示目前有多少个字符设备在使用该驱动程序。当使用rmmod卸载模块时,如果count成员不为0,那么系统不允许卸载模块。
list结构是一个双向链表,用于将其他结构体连接成一个双向链表。structlist_head {
struct list_head *next, *prev;
};
cdev结构体的list成员连接到了inode结构体i_devices成员。其中i_devices也是一个list_head结构。这样,使cdev结构与inode结点组成了一个双向链表。inode结构体表示/dev目录下的设备文件。
每一个字符设备在/dev目录下都有一个设备文件,打开设备文件就相当于打开相应的字符设备。例如应用程序打开设备文件A,那么系统会产生一个inode结点。这样可以通过inode结点的i_cdev字段找到cdev字符结构体。通过cdev的ops指针,就能找到设备A的操作函数。
可以使用如下宏调用来获得主、次设备号:
MAJOR(dev_t dev)
MINOR(dev_t dev)
一个 cdev一般它有两种定义初始化方式:静态的和动态的。
静态内存定义初始化:
struct cdevmy_cdev;
cdev_init(&my_cdev,&fops);
my_cdev.owner= THIS_MODULE;
动态内存定义初始化:
struct cdev*my_cdev = cdev_alloc();
my_cdev->ops= &fops;
my_cdev->owner= THIS_MODULE;
两种使用方式的功能是一样的,只是使用的内存区不一样,一般视实际的数据结构需求而定。
下面贴出了两个函数的代码,以具体看一下它们之间的差异。
由此可见,两个函数完成都功能基本一致,只是cdev_init() 还多赋了一个 cdev->ops 的值。
初始化 cdev后,需要把它添加到系统中去。为此可以调用 cdev_add() 函数。传入 cdev 结构的指针,起始设备编号,以及设备编号范围。
关于 kobj_map()函数就不展开了,我只是大致讲一下它的原理。内核中所有都字符设备都会记录在一个 kobj_map 结构的 cdev_map变量中。这个结构的变量中包含一个散列表用来快速存取所有的对象。kobj_map() 函数就是用来把字符设备编号和 cdev 结构变量一起保存到cdev_map 这个散列表里。当后续要打开一个字符设备文件时,通过调用 kobj_lookup() 函数,根据设备编号就可以找到 cdev结构变量,从而取出其中的 ops 字段。
当一个字符设备驱动不再需要的时候(比如模块卸载),就可以用cdev_del() 函数来释放 cdev 占用的内存。
其中cdev_unmap() 调用 kobj_unmap() 来释放 cdev_map 散列表中的对象。kobject_put() 释放 cdev 结构本身。
学习字符设备模型
基础数据结构
字符设备模型
每个字符驱动由一个 cdev 结构来表示.
在设备驱动模型(device driver model)中, 使用 (kobject mapping domain)来记录字符设备驱动.
这是由 struct kobj_map 结构来表示的. 它内嵌了255个struct probe指针数组
kobj_map由全局变量 cdev_map 引用: static struct kobj_map *cdev_map;
相关函数说明:
cdev_alloc() 用来创建一个cdev的对象
cdev_add() 用来将cdev对象添加到驱动模型中,其主要是通过kobj_map()来实现的.
kobj_map() 会创建一个probe对象,然后将其插入cdev_map中的某一项中,并关联probe->data 指向cdev
struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev,int *index)
根据设备号,在cdev_map中查找其cdev对象内嵌的kobject.(probe->data->kobj),返回的是cdev的kobject
2. 字符设备的设备号
字符设备的主,次设备号的分配:
全局数组 chrdevs 包含了255(CHRDEV_MAJOR_HASH_SIZE 的值)个 structchar_device_struct的元素.
每一个对应一个相应的主设备号.
如果分配了一个设备号,就会创建一个 struct char_device_struct 的对象,并将其添加到 chrdevs 中.
这样,通过chrdevs数组,我们就可以知道分配了哪些设备号.
相关函数:
register_chrdev_region( ) 分配指定的设备号范围
alloc_chrdev_region( ) 动态分配设备范围
他们都主要是通过调用函数__register_chrdev_region() 来实现的
要注意,这两个函数仅仅是注册设备号! 如果要和cdev关联起来,还要调用cdev_add()
register_chrdev( ) 申请指定的设备号,并且将其注册到字符设备驱动模型中.
它所做的事情为:
1. 注册设备号, 通过调用 __register_chrdev_region() 来实现
2. 分配一个cdev, 通过调用 cdev_alloc() 来实现
3. 将cdev添加到驱动模型中, 这一步将设备号和驱动关联了起来. 通过调用 cdev_add() 来实现
4. 将第一步中创建的 struct char_device_struct 对象的 cdev 指向第二步中分配的cdev.由于register_chrdev()是老的接口,这一步在新的接口中并不需要.
3. 文件系统中对字符设备文件的访问
对于一个字符设备文件, 其inode->i_cdev 指向字符驱动对象cdev, 如果i_cdev为 NULL,则说明该设备文件没有被打开.
由于多个设备可以共用同一个驱动程序.所以,通过字符设备的inode 中的i_devices 和 cdev中的list组成一个链表
首先,系统调用open打开一个字符设备的时候, 通过一系列调用,最终会执行到 chrdev_open.
(最终是通过调用到def_chr_fops中的.open, 而def_chr_fops.open = chrdev_open.这一系列的调用过程,本文暂不讨论)
int chrdev_open(struct inode * inode, struct file * filp)
chrdev_open()所做的事情可以概括如下:
1. 根据设备号(inode->i_rdev), 在字符设备驱动模型中查找对应的驱动程序, 这通过kobj_lookup()来实现, kobj_lookup()会返回对应驱动程序cdev的kobject.
2. 设置inode->i_cdev , 指向找到的cdev.
3. 将inode添加到cdev->list的链表中.
4. 使用cdev的ops 设置file对象的f_op
5. 如果ops中定义了open方法,则调用该open方法
6. 返回.
执行完 chrdev_open()之后,file对象的f_op指向cdev的ops,因而之后对设备进行的read,write等操作,就会执行cdev的相应操作.
此处3个分析转载自http://blog.csdn.net/cuijianzhongswust/article/details/6887993
分享到:
相关推荐
在Linux系统中,设备可以被分为字符设备、块设备和网络设备等不同类型,每种设备都有相应的驱动模型和接口。 1. **字符设备驱动**:字符设备以流的形式传输数据,通常不支持随机访问,例如串口、键盘和鼠标等。字符...
总的来说,《Linux设备驱动开发详解-基于最新的Linux4.0内核》的源码提供了丰富的实践案例,是学习Linux驱动开发的宝贵资源。读者可以通过阅读和实践这些代码,深入了解Linux内核工作机制,提高驱动程序设计和调试的...
Linux设备驱动主要分为字符设备、块设备和网络设备等类型,每种类型都有其特定的接口和操作方式。字符设备驱动处理单个数据流,如键盘或串口;块设备驱动则用于处理连续的数据块,如硬盘或闪存设备;网络设备驱动则...
这些示例涵盖了从简单的字符设备到复杂的网络设备驱动,对于提升Linux驱动开发能力非常有帮助。 总之,《Linux设备驱动开发详解-基于最新的Linux4.0内核》一书提供了丰富的实践案例,结合源码分析,是学习Linux驱动...
要编写一个字符设备驱动程序,首先需要理解Linux设备模型。Linux将所有设备分为字符设备和块设备,每个设备都有一个唯一的设备号,由主设备号和次设备号组成,它们在/dev目录下的设备文件中体现。在注册字符设备时,...
在Linux操作系统中,设备驱动是连接硬件与操作系统内核的关键组件。它们负责处理硬件操作,使得内核能够高效地管理硬件资源。...无论你是初学者还是经验丰富的开发者,都能从中受益匪浅,提升你的Linux驱动开发技能。
linux字符设备驱动模型
在Linux中,字符设备驱动通常基于字符设备文件模型,它由设备号(major和minor number)标识,用于区分不同的设备。驱动程序通过注册到内核的字符设备接口来提供服务,包括打开、关闭、读取、写入等操作。 1. **...
在Linux中,设备驱动通常分为字符设备驱动、块设备驱动和网络设备驱动等类型。这些驱动程序允许操作系统执行如读写数据、配置设备参数等操作。 二、ARM架构与6410处理器 ARM(Advanced RISC Machines)架构是一种...
Linux设备模型采用一种分层的结构,包括总线、设备、驱动和控制器。总线(如PCI、USB)是连接硬件组件的接口,设备是在总线上挂载的硬件实体,驱动则是控制这些设备的软件,而控制器是管理总线的硬件。这种层次化的...
《Linux设备驱动开发详解》是一本深度探讨Linux内核驱动程序开发的专业书籍,它以Linux 4.0内核为背景,为驱动工程师提供了一条深入理解与实践Linux设备驱动的路径。这本书涵盖了许多关键的知识点,对于想要在Linux...
在Linux操作系统中,设备驱动程序是操作系统内核与硬件设备之间的桥梁,它们使得操作系统能够与硬件进行通信。本文将深入探讨如何编写一...对于初学者来说,逐步学习并实践这些概念是提升Linux驱动开发技能的有效途径。
2. **设备模型**:讲解Linux设备模型,如总线、设备和驱动模型,如何通过udev管理系统识别和配置设备。 3. **字符设备驱动**:深入讲解字符设备驱动的开发,包括设备节点的创建、ioctl命令、中断处理等。 4. **块...
Linux设备驱动分为字符设备驱动、块设备驱动和网络设备驱动等类型,每种都有其特定的API和工作方式。 二、设备模型 Linux设备模型提供了一套统一的方式来表示和管理系统的硬件设备。它包括设备节点、总线、设备和...
1. **设备模型**:Linux设备模型是一套用于组织和管理硬件设备的框架,包括设备分类(字符设备、块设备、网络设备等)、总线(PCI、USB等)、设备注册和注销等。《Linux设备驱动程序学习(16)-Linux设备模型》和...
2. **设备模型**:Linux设备模型是理解驱动程序的关键,书中详细阐述了设备节点、主设备号、次设备号的概念,以及现代内核中的统一设备模型(Udev),这有助于管理和注册设备。 3. **驱动程序架构**:书中会讲解...
本篇将深入探讨Linux设备模型,包括总线、设备、驱动程序和类的概念,以及它们在设备驱动程序中的作用。 **一、Linux设备模型** Linux设备模型是一个抽象层次,它简化了设备的管理,并提供了一种统一的方式来注册...
总之,编写Linux字符设备驱动是一项技术性极强的任务,它涉及到内核编程、同步机制和设备驱动模型的理解。通过实现一个简单的聊天程序,我们可以直观地看到字符设备驱动如何在用户空间和内核空间之间搭建桥梁,提供...
Linux设备驱动程序学习(1)-字符设备驱动程序 ·Linux设备驱动程序学习(0)-Hello, world!模块 ·Linux设备驱动程序学习(2)-调试技术 ·Linux设备驱动程序学习(3)-并发和竞态 ·Linux设备驱动程序学习(4)-...