您的位置 首页 电子

了解并学习Linux设备驱动的基础知识

了解并学习Linux设备驱动的基础知识-设备驱动充当了硬件和应用软件之间的纽带,它使得应用软件只需要调用系统软件的应用编程接口(API)就可让硬件去完成要求的工作。

设备驱动充当了硬件和运用软件之间的枢纽,它使得运用软件只需求调用体系软件的运用编程接口(API)就可让硬件去完结要求的作业。本文首要讲解了Linux设备驱动与硬件的联系,Linux设备驱动的开发方式以及内核中相关的重要根底数据结构。

设备驱动与硬件的联系

对设备驱动最浅显的解说便是“唆使硬件设备举动”。驱动与底层硬件直接打交道,依照硬件设备的详细作业方式,读写设备的寄存器,完结设备的轮询、中止处理、 DMA 通讯,进行物理内存向虚拟内存的映射等,终究让通讯设备能收发数据,让显现设备能显现文字和画面,让存储设备能记载文件和数据。

设备分类

Linux对将外设分为3类:

字符设备

字符设备指那些有必要以串行次序顺次进行拜访的设备,如触摸屏、磁带驱动器、鼠标等。

块设备

块设备能够用恣意次序进行拜访,以块为单位进行操作,如硬盘、软驱等。

网络设备

网络设备面向数据包的接纳和发送而规划,它并不对应于文件体系的节点。

整体框图

机制与战略

机制着重“供给什么才能”,而战略旨在“怎么运用这些才能”。因而驱动开发需求恪守的是驱动程序的人物是供给机制, 而不是战略。
编写内核代码来存取硬件, 可是不能强加特别的战略给用户, 由于不同的用户有不同的需求。驱动应当做到使硬件可用, 将一切关于怎么运用硬件的作业留给运用程序。

内核模块

Linux 供给了一种代码动态地加载到内核中机制,这种机制被称为模块(Module)。具有如下特色:

模块自身不被编译入内核映像, 然后操控了内核的巨细。

模块一旦被加载,它就和内核中的其他部分彻底相同。

可动态加载与移除,不需重启体系,节省开发时刻。

模块放在用户空间,这部分代码能够不开源。

因而驱动大都状况以内核模块的方式加载到内核。

组成

一个 Linux 内核模块首要由如下几个部分组成:

模块加载函数(一般需求)

当经过 insmod 或 modprobe 指令加载内核模块时,模块的加载函数会主动被内核履行,完结本模块的相关初始化作业。static int __init iniTIalizaTIon_funcTIon(void){ /* 初始化代码 */}module_init(iniTIalization_function);

模块卸载函数(一般需求)

当经过 rmmod 指令卸载某模块时,模块的卸载函数会主动被内核履行,完结与模块卸载函数相反的功用。static void __exit cleanup_function(void){ /* 开释代码 */}module_exit(cleanup_function);

模块答应证声明(有必要)

答应证( LICENSE)声明描绘内核模块的答应权限,假如不声明 LICENSE,模块被加载时,将收到内核被污染 ( kernel tainted)的正告。在 Linux 2.6 内核中,可接受的 LICENSE 包括“ GPL”、“ GPL v2”、“ GPL and additional rights”、“ Dual BSD/GPL”、“ Dual MPL/GPL” 和“ Proprietary”。

模块参数(可选)

模块参数是模块被加载的时分能够被传递给它的值,它自身对应模块内部的全局变量。module_param(参数名,参数类型,参数读/写权限);module_param_array(数组名,数组类型,数组长,参数读/写权限);

模块导出符号(可选)

内核模块能够导出符号( symbol,对应于函数或变量),这样其他模块能够运用本模块中的变量或函数。EXPORT_SYMBOL(符号名);EXPORT_SYMBOL_GPL(符号名);

模块作者等信息声明(可选)

MODULE_AUTHOR(author);MODULE_DESCRIPTION(description);MODULE_VERSION(version_string);MODULE_DEVICE_TABLE(table_info);MODULE_ALIAS(alternate_name);

编译

# Makefile2.6TARGET = demo_moduleifneq ($(KERNELRELEASE),)#kbuild syntax. dependency relationshsip of files and target modules are listed here.obj-m := $(TARGET).o else# build from shell directly not in kernel rootCURDIR = $(shell pwd)KVER := $(shell uname -r)KDIR := /lib/modules/$(KVER)/buildall: $(MAKE) -C $(KDIR) M=$(CURDIR) modulesclean: $(MAKE) -C $(KDIR) M=$(CURDIR) cleaninsert: sudo insmod $(TARGET).koremove: sudo rmmod $(TARGET)endif

重要的数据结构

大部分的根底性的驱动操作包括3个重要的内核数据结构, 称为 file_operations, file, 和 inode。

file_operations

file_operations 结构体中的成员函数是设备驱动程序规划的主体内容,这些函数实践会在运用程序进行 Linux 的 open()、 write()、 read()、 close()等体系调用时终究被调用。

struct file_operations { struct module *owner; /* 具有该结构的模块的指针,一般为 THIS_MODULES */ loff_t(*llseek)(struct file *, loff_t, int); /* 用来修正文件当时的读写方位 */ ssize_t(*read)(struct file *, char __user *, size_t, loff_t*); /* 从设备中同步读取数据 */ ssize_t(*write)(struct file *, const char __user *, size_t, loff_t*); /* 向设备发送数据*/ ssize_t(*aio_read)(struct kiocb *, 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); /* 仅用于读取目录,关于设备文件,该字段为 NULL */ unsigned int(*poll)(struct file *, struct poll_table_struct*); /* 轮询函数,判别现在是否能够进行非堵塞的读取或写入*/ int(*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); /* 履行设备 I/O 操控指令*/ long(*unlocked_ioctl)(struct file *, unsigned int, unsigned long); /* 不运用 BLK 的文件体系,将运用此种函数指针替代 ioctl */ long(*compat_ioctl)(struct file *, unsigned int, unsigned long); /* 在 64 位体系上, 32 位的 ioctl 调用,将运用此函数指针替代*/ int(*mmap)(struct file *, struct vm_area_struct*); /* 用于恳求将设备内存映射 int(*open)(struct inode *, struct file*); /* 翻开 */ int(*release)(struct inode *, struct file*); /* 封闭*/ int (*fsync) (struct file *, struct dentry *, int datasync); /* 改写待处理的数据*/ int(*aio_fsync)(struct kiocb *, int datasync); /* 异步 fsync */ int(*fasync)(int, struct file *, int); /* 告诉设备 FASYNC 标志发生变化*/ …};

file

file 结构体代表一个翻开的文件(设备对应于设备文件),体系中每个翻开的文件在内核空间都有一个相关的 struct file。它由内核在翻开文件时创立,并传递给在文件上进行操作的任何函数。在文件的一切实例都封闭后,内核开释这个数据结构。

struct file { const struct file_operations *f_op; /* 和文件相关的操作*/ unsigned int f_flags; /*文件标志,如 O_RDONLY、 O_NONBLOCK、 O_SYNC*/ fmode_t f_mode; /*文件读/写方式, FMODE_READ 和 FMODE_WRITE*/ loff_t f_pos; /* 当时读写方位*/ void *private_data; /*文件私有数据,可存储自定义数据的指针*/ …};

inode

VFS inode 包括文件拜访权限、属主、组、巨细、生成时刻、拜访时刻、最终修正时刻等信息。它是 Linux 办理文件体系的最基本单位,也是文件体系衔接任何子目录、文件的桥梁。

struct inode { umode_t i_mode; /* inode 的权限 */ uid_t i_uid; /* inode 具有者的 id */ gid_t i_gid; /* inode 所属的群组 id */ dev_t i_rdev; /* 若是设备文件,此字段将记载设备的设备号 */ loff_t i_size; /* inode 所代表的文件巨细 */ struct timespec i_atime; /* inode 最近一次的存取时刻 */ struct timespec i_mtime; /* inode 最近一次的修正时刻 */ struct timespec i_ctime; /* inode 的发生时刻 */ unsigned long i_blksize; /* inode 在做 I/O 时的区块巨细 */ unsigned long i_blocks; /* inode 所运用的 block 数,一个 block 为 512 byte*/ struct block_device *i_bdev; /*若是块设备,为其对应的 block_device 结构体指针*/ struct cdev *i_cdev; /*若是字符设备,为其对应的 cdev 结构体指针*/ …};
 

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qiche/dianzi/89613.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部