Linux驱动程序概述

Linux设备驱动程序是为特定的硬件提供给应用程序的一组标准化接口,它隐藏了设备工作的细节。用户程序通过标准化系统调用,这些调用和特定的硬件是无关的,再由Linux内核调用特定的设备驱动程序操作和控制特定的实际的硬件设备。其中,Linux系统设备分为三种类型:

  • 字符设备(character device)
  • 块设备(block device)
  • 网络接口(network interface)

本篇文章中,主要谈论字符设备驱动程序的设计。
字符设备是能够像字节流一样被访问的设备,一般不使用缓存技术。字符设备驱动程序最少应实现open、close、read和write系统调用。典型的字符设备例子是终端设备(/dev/console)和串口(/dev/ttyS0)。

字符驱动程序的调用过程


如上图,用户想要调用Linux设备驱动函数对设备进行操作时,由Linux系统调用来间接调用设备驱动函数,此时系统由用户态陷入内核态,完成对设备的操作后(即完成内核态数据和用户态数据的交换),操作系统又返回用户态。

驱动程序的一些基本知识

主设备号和次设备号

Linux系统为每一个设备分配了一个主设备号和次设备号,主设备号标识一类设备对应的驱动程序,次设备号用来标识一类设备中的某个具体设备。比如说:现在有打印机这个设备,主设备号就只用来标识打印机这类设备,区别于其他如鼠标,传真机等设备;而次设备号是用来区别不同打印机,如打印机A和打印机B,它俩主设备号一样,但次设备号不同。

设备文件的操作

Linux系统访问设备就像访问文件一样,例如打开设备使用系统调用open(),关闭设备使用系统调用close()。读写设备使用系统调用read()和write()。在Linux内核中,字符设备使用struct file_operations结构来定义设备的各种操作集合,结构中的各个函数分别响应同名或类似的名称的系统调用。struct file_operations结构在Linux系统下的定义如下:

struct file_operations{struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t*);ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t*);ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void*);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*dir_notify)(struct file *filp, unsigned long arg);int (*flock) (struct file *, int, struct file_lock *);
};

主要函数的作用

ioctl函数

int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

ioctl 函数提供用户程序对设备执行特定的命令的方法,比如设置设备驱动程序内部参数,控制设备操作特性,或其他不是读也不是写的操作等。调用成功返回非负值。

open函数

int (*open) (struct inode *, struct file *);

open 函数用来打开设备。如果该函数没有实现,系统调用 open 总是成功,但驱动程序得不到任何打开设备的通知。

read/write函数

ssize_t (*read) (struct file * filp, char __user * buffer, size_t size, loff_t * opps);
ssize_t (*write) (struct file * filp, const char __user * buffer, size_t size, loff_t * opps);

(指针参数 filp 为进行读取(写)信息的目标文件,指针参数buffer 为对应放置信息的缓冲区(即用户空间内存地址),参数size为要读取的信息长度,参数 opps 为读(写)的位置相对于文件开头的偏移,在读取信息后,这个指针一般都会移动,移动的值为要读取信息的长度值)。
如果返回值为非负,则操作成功。

llseek函数

loff_t (*llseek) (struct file * filp , loff_t p, int orig);

指针参数filp为进行读取信息的目标文件结构体指针;参数 p 为文件定位的目标偏移量;参数orig为对文件定位的起始地址,其中,orig=0,则表示从文件头开始;orig=1,则表示从当前位置开始;origin=2,表示从文件末尾开始。

llseek 方法用作改变文件中的当前读/写位置, 并且新位置作为(正的)返回值.

loff_t 参数是一个"long offset", 并且就算在 32位平台上也至少 64 位宽。

编写字符设备驱动程序,主要是实现struct file_operations结构中的各个函数。当然,驱动程序并不是要实现所有的这些函数,可以根据实际设备需要实现必要的函数即可。

模块注册和卸载的函数调用

在 Linux 系统中注册设备时,通常需要传递三个重要参数:主设备号设备名称设备文件结构
主设备号是在系统内是唯一标识设备类型的定义,向内核申请设备注册或卸载时,都需要传递主设备号。主设备号的定义有两种方法:

  1. 指定一常数作为主设备号,只要不与已有设备号冲突,即可把该设备号唯一地指派给该设备;
  2. 以设备号0进行注册申请,由系统返回一个可用设备号作为主设备号。

设备注册或卸载时还包括传递一个设备名称,用户程序使用这个名称来打开设备。
设备是以文件的形式存在的,所以设备注册时需要使用一个文件结构struct file_operations定义,内核使用此结构定位驱动程序的操作函数。
字符设备的注册通过调用register_chrdev来注册,通过unregister_chrdev_region来卸载:

/* 字符设备注册函数 */
int register_chrdev (unsigned int major, const char *name, struct file_operations *fops);
/*字符设备卸载函数*/
static inline void unregister_chrdev(unsigned int major, const char *name);

Linux设备驱动程序设计(一)相关推荐

  1. Linux USB设备驱动程序设计 和 USB下载线驱动设计

    Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...

  2. linux驱动程序设计21 Linux设备驱动的调试

    本章导读 "工欲善其事,必先利其器",为了方便进行Linux设备驱动的开发和调试,建立良好的开发环境很重 要,还要使用必要的工具软件以及掌握常用的调试技巧等. 21.1节讲解了Li ...

  3. 深入浅出:Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  4. linux设备驱动学习(二)——字符设备编写及测试

    一.字符设备体结构介绍 1.字符设备作为linux内核三大驱动设备之一,主要完成字节的读写操作,常见的应用有鼠标.键盘等,结构体形式如下所示: struct cdev{ struct kobject ...

  5. Linux设备驱动的分层设计思想

    1.1 设备驱动核心层和例化 在面向对象的程序设计中,可以为某一类相似的事物定义一个基类,而具体的事物可以继承这个基类中的函数.如果对于继承的这个事物而言,其某函数的实 现与基类一致,那它就可以直接继 ...

  6. Linux 设备驱动开发思想 —— 驱动分层与驱动分离

    前面我们学习I2C.USB.SD驱动时,有没有发现一个共性,就是在驱动开发时,每个驱动都分层三部分,由上到下分别是: 1.XXX 设备驱动 2.XXX 核心层 3.XXX 主机控制器驱动 而需要我们编 ...

  7. 蜕变成蝶~Linux设备驱动之字符设备驱动

    一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流 ...

  8. Linux USB驱动程序设计

    Linux USB驱动程序设计 1. USB发展史 USB(Universal Serial Bus ),通用串行总线,是一种外部总线标准,用于规范电脑与外部设备的连接和通讯. USB是在1994年底 ...

  9. linux驱动基础开发0——linux 设备驱动概述-转

    目前,Linux软件工程师大致可分为两个层次: (1)Linux应用软件工程师(Application Software Engineer):       主要利用C库函数和Linux API进行应用 ...

最新文章

  1. 测量150kHz接收电路的主要的一些特性:扫频,线性,工作电压影响
  2. python中的break+while break+for
  3. 计算机突然蓝屏无法启动_为什么计算机无法立即启动?
  4. 类的静态成员函数带来了什么好处,应该在什么时候使用?
  5. 计划任务中使用NT AUTHORITY\SYSTEM用户和普通管理员用户有什么差别
  6. (转)如何用PHP/MySQL为 iOS App 写一个简单的web服务器(译) PART1
  7. 虚拟机安装CentOS系统详细步骤。
  8. Android平板软件推荐,新人看过来 安卓平板装机必备软件推荐
  9. 【搜索力】提高你搜索能力的必备技巧
  10. 【saltstack】认证失败,无法生成minion_master.pub问题处理总结
  11. android时间格式am pm,pm时间(am.pm正确时间书写格式)
  12. mysql的right函数_MySQL数据库中系统函数right功能简介
  13. linux关键vi按什么键n,linux vi 使用方法
  14. Win 10 远程桌面连接
  15. oracle数据库怎么ping,Oracle中tnsping命令解析
  16. 【数论】同余(五):多元线性同余方程
  17. 一篇搞懂Python中的随机数
  18. java发邮件出现535错误,Java邮件发送的几个常见错误及异常
  19. 深入理解JVM之三:垃圾回收算法
  20. “香港一卡通”收費表

热门文章

  1. Cobalt Strike:使用已知的私钥解密流量 -Part 2
  2. 计算1+12+123+1234+12345
  3. ARAS plm安装,各种踩坑
  4. 拓扑排序:利用kahn算法。c++
  5. HTML5小游戏动手做(二):使用PIXI引擎制作坦克大战游戏
  6. 电脑游戏声音如何录制?
  7. windows10 ms-settings:display解决方法
  8. acme.sh从 letsencrypt 生成SSL免费证书并自动更新证书
  9. 群表示论之Q8四元数群的特征标表和二阶不可约复表示
  10. 使用SonarTS创建进行typescript代码质量扫描