Linux驱动开发入门与实践(一)
来源:互联网 发布:湖南软件职业学院专业 编辑:程序博客网 时间:2024/06/05 14:49
最近这一段时间,把之前学的linux基础的东西捡了回来,正式开始接触驱动了。接触后发现底层的东西还是相当的繁琐,内核里的宏定义数不胜数,结构体,指针更是扑面而来。驱动主要分为三部分,分别是字符设备、块设备以及网络接口设备。这里先总结下简单字符设备驱动相关的东西。
参考资料:1.《Linux驱动开发入门与实践》 郑强
2.《国嵌培训资料以及视频》
参考资料1个人觉得不是很适合拿来上手,虽然讲的点多,但是却不细致。而2讲的点少,但比较细也比较浅显。
字符设备驱动:
字符设备理解起来可以和块设备进行区分理解。
字符=只能一个一个字节读写
块=可以从任意位置读取一定长度数据的设备,不必按照先后顺序。
如果对应上实物的话:字符设备有:鼠标、键盘、串口、控制台···
块设备有:SD卡、硬盘、磁盘、U盘···
Linux具体是怎样去操作设备驱动的?
在Linux系统中,每个字符设备或者块设备都在 /dev目录下有对应一个设备文件。Linux对设备进行操控,本质上就是通过这些文件来操作的。这样相当于有了一套标准,程序员便可以撇开设备的差异化从而按照标准进行编程。
区分一个现成的Linux系统当前的设备文件的属性,只需要cd /dev 然后 ls -l
出现以下条目:
crw-rw----+ 1 root root 14, 12 12-21 22:56 adsp
第一个字符c 就表示char 字符型设备 ,b则表示block 块设备。而5、6字段分别表示主设备号和次设备号。
为什么需要主设备号和次设备号呢?
主设备号用来区分不同类型的设备,如USB设备和串口设备。次设备号则是用来区分某一类型设备中不同的子设备。如串口设备不止一种,所以通过此设备号进行区分。
主设备号和次设备号的表示(具体代码实现)
Linux中用dev_t 类型来表示设备号。其实它本质上就是一个无符号长整型,
typedef u_long dev_t
u_long 在32位机里为4个字节 ,在64位里为8字节。由于自己学的是ARM,以32位机为例。其中高12位表示主设备号,低20位表示次设备号。
设备号的获得与申请方式:
主要有2种,第一种为静态申请,第二种自然就是动态申请。采用的方法不同,前期的基础工作也就不同。
先说说静态申请:静态申请毫无疑问需要程序员自己给分配一个设备号,那么怎样判断一个设备号是否可用呢?或者说当前系统里没有被其他设备占用呢?
方法:可以读取 /proc/devices 文件来获得设备号。
指令如下:cat /proc/devices
知道当前系统占用的设备号后,比如要需要设置的设备号为200,那么怎么构建该设备号呢?
Linux系统采用MKDEV来实现,其中
dev_t devno=MKDEV(ma,mi);其中ma为主设备号,mi为次设备号。
构建完设备号之后,还需要进行申请,静态申请的方法为:
int register_chrdev_region(dev_t from, unsigned count , const char *name); 头文件:<fs/char_dev.c>
from 是要分配设备号范围起始值,count表示需要申请设备号的个数。 name则是设备名称,注意不能超过64字节。
动态分配:静态分配由于人为因素,很可能导致冲突,所以Linux自己给自动分配一个未使用的设备号则更加有利。
动态申请不需要自己构建设备号,调用函数:
int alloc_chrdev_region(&dev_t *dev,unsigned baseminor,unsigned count, const char *name)
成功后返回的设备号保存在dev指向的dev_t 类型的变量里。baseminor 为次设备号的起始号,count为子设备数 name为设备名称。
申请完后,要将字符设备注册到系统中,才能使用。
cdev 用来描述字符设备。
struct cdev {
struct kobject kobj;
struct module *owner;/*指向包含该结构的模块的指针,用于引用计数*/
const struct file_operations *ops;/*指向字符设备操作函数集的指针*/
struct list_head list; /*该结构将使用该驱动的字符设备连成一个链表*/
dev_t dev; /*该字符设备的起始设备号*/
unsigned int count;/*使用该字符设备驱动的设备数量*/
};
kobj结构用于内核管理字符设备,驱动开发人员一般不使用。
ops是指向file_operations 操作函数结构体指针。
list为双向链表,用于将其他结构体连接成一个双向链表,其连接到inode结构体i_devices成员。而i_devices也是一个list_head结构。这样使得cdev结构与inode结点组成一个双向链表。
文件系统中对字符设备文件的访问
对于一个字符设备文件, 其inode->i_cdev 指向字符驱动对象cdev, 如果i_cdev为 NULL ,则说明该设备文件没有被打开.
由于多个设备可以共用同一个驱动程序.所以,通过字符设备的inode 中的i_devices 和 cdev中的list组成一个双向链表。inode表示/dev下的设备文件。每一个字符设备在/dev下都有一个设备文件,打开设备文件就相当于打开相应的字符设备。例如应用程序打开设备文件A,那么系统就会产生一个inode结点,这样可以通过inode结点的i_cdev字段找到cdev字符结构体。
首先,系统调用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的相应操作.
- Linux驱动开发入门与实践(一)
- Linux设备驱动开发详解:入门与编程实践
- linux驱动实践(一)--开篇
- 数字图像处理开发入门与编程实践 笔记一
- Linux字符设备驱动入门(一)
- git入门与实践(一)
- GitHub入门与实践一
- Linux驱动开发(一)——驱动开发基础
- R语言入门与实践(一)Linux版R语言安装
- 驱动入门 一 搭建驱动开发环境
- appcan学习与开发实践(一)
- Linux设备驱动入门(一)
- 嵌入式Linux设备驱动开发(一)
- linux驱动模块开发(一)
- linux 内核驱动开发入门
- Linux内核与驱动开发学习总结:DMA与中断(一)
- Linux驱动入门学习(一):入门介绍
- 【嵌入式Linux驱动开发】三、字符设备驱动(一)
- java swing setEnabled setVisible区别
- 安卓最佳实践之布局优化
- smarty内建函数和自定义插件函数的使用
- html中去除ul li前的黑点
- Android 5.1系统源码Wifi模块中wifiConfigController源码分析
- Linux驱动开发入门与实践(一)
- 分散加载文件sct 的书写经验
- 【游戏开发学习之】深与浅:层级结构的设计原则
- 使用loadrunner下载资源时步骤下载超时(120seconds已过期)
- 北美Google Play攻略:如何让产品被推荐
- ubuntu下apache服务器开启url重写
- Fragment传递参数
- 学嵌入式为什么要学Linux?
- kermit配置/反汇编/c和汇编混合编程/计算机存储介质/GPIO编程