嵌入式系统原理与技术课件:第10章 字符设备和驱动程序设计(初稿).pptx
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《嵌入式系统原理与技术课件:第10章 字符设备和驱动程序设计(初稿).pptx》由用户(罗嗣辉)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 嵌入式系统原理与技术课件:第10章 字符设备和驱动程序设计初稿 嵌入式 系统 原理 技术 课件 10 字符 设备 驱动程序 设计 初稿
- 资源描述:
-
1、1、字符设备驱动框架2、字符设备驱动开发3、GPIO驱动概述4、串行总线概述5、I2C总线驱动开发1、字符字符设备驱动设备驱动框架框架 Linux的一个重要特点就是将所有的设备都当作文件来处理,其中就包括设备文件,它们可以使用和操作文件相同的、标准的系统调用接口来完成打开、关闭、读写和I/O控制操作,而驱动程序的主要任务也就是要实现这些系统调用函数。设备驱动程序为应用程序屏蔽了硬件的细节。字符设备驱动程序是嵌入式Linux最基本、也是最常用的驱动程序。它的功能非常强大,几乎可以描述不涉及挂载文件系统的所有硬件设备。字符设备驱动程序的实现方式分为两种:一种是直接编译进内核,另一种是以模块方式加载
2、,然后在需要使用驱动时加载。2、字符设备驱动开发对字符设备的访问是通过文件系统内的设备文件进行的,或者称为设备节点。它们通常位于/dev目录。表示字符设备的设备文件可以通过“ls -l”命令输出的第一列中的“c”来识别,而块设备则用“b”标识。主设备号用来标识该设备的种类,也标识了该设备所使用的驱动程序;次设备号由内核使用,标识使用同一设备驱动程序的不同硬件设备。设备设备号号在Linux内核中,使用dev_t类型来表示设备号,这个类型在头文件中定义。typedef _u32 _kernel_dev_t;typedef _kernel_dev_tdev_t;dev_t是一个32位的无符号数,其高
3、12位用来表示主设备号,低20位用来表示次设备号。在2.6内核中,可以容纳大量的设备,而不像先前的内核版本最多只能使用255个主设备号和255个次设备号。内核主要提供了三个操作dev_t类型的函数,它们分别是: MAJOR(dev)、MINOR(dev)和MKDEV(ma, mi)。 其中MAJOR(dev)用于获取主设备号。 MINOR(dev)则用于获取次设备号。 MKDEV(ma, mi) 根据主设备号ma和次设备号mi构造dev_t设备号。在头文件中给出了这些宏的定义#define MINORBITS20#define MINORMASK(1U MINORBITS)#define MI
4、NOR(dev)(unsigned int) (dev) & MINORMASK)#define MKDEV(ma,mi) (ma) MINORBITS) | (mi)注册和注销设备号在建立一个字符设备之前,驱动程序首先要做的一件事是向内核请求分配一个或多个设备号。内核专门提供了字符设备号管理的函数接口:int register_chrdev_region(dev_t first, unsigned int count, const char *name);int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned
5、 int count, const char *name);void unregister_chrdev_region(dev_t first, unsigned int count);register_chrdev_region函数和alloc_chrdev_region函数用于分配设备号,它们的区别是后者是以动态的方式分配的。unregister_chrdev_region函数则用于释放设备号。关键关键数据结构数据结构多数情况下,基本的驱动程序操作都会涉及到内核提供的三个关键数据结构,分别是file_operations、file和inode,它们都在头文件中定义。 struct file
6、_operations struct file struct inodefile_operationsfile_operations结构体描述了一个文件操作所需要的所有函数。这组函数是以函数指针的形式给出的,它们是字符设备驱动程序设计的主要内容。每个打开的文件,在内核里都用file结构体表示,这个结构体中有一个成员为f_op,它是指向一个file_operations结构体的指针。通过这种形式将一个文件同它自身的操作函数关联起来,这些函数实际上是系统调用的底层实现。在用户空间的应用程序调用内核提供的open、close、read、write等系统调用时,实际上最终会调用这些函数。file_op
7、erations编写驱动程序的主要工作就是实现这些函数中的一部分,具体实现哪些函数因实际需要而定。对于一个字符设备来说,一般只要实现open、release、read、write、mmap、ioctl这几个函数。随着内核版本的不断改进,file_operations结构体的规模也越来越大,它的定义如下所示:struct file_operations /指向拥有该结构的模块的指针,一般初始化为THIS_MODULE struct module *owner; /用来改变文件中的当前读/写位置 loff_t (*llseek) (struct file *, loff_t, int); /用来从
8、设备中读取数据 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 *, const struct iovec *, unsigned long, loff_t); /初始化一个异步写入操作 ssize_t (*aio_write) (struct kiocb
9、*, const struct iovec *, unsigned long, loff_t); /用来读取目录,对于设备文件,该成员应当为NULL int (*readdir) (struct file *, void *, filldir_t); /轮询函数,查询对一个或多个文件描述符的读或写是否会阻塞 unsigned int (*poll) (struct file *, struct poll_table_struct *); /用来执行设备I/O操作命令 int (*ioctl) (struct inode *, struct file *, unsigned int, unsig
10、ned long); /不使用BKL文件系统,将使用此函数代替ioctl long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); /在64位系统上,使用32位的ioctl调用将使用此函数代替long (*compat_ioctl) (struct file *, unsigned int, unsigned long);/用来将设备内存映射到进程的地址空间int (*mmap) (struct file *, struct vm_area_struct *);/用来打开设备int (*open) (struct
11、inode *, struct file *);/执行并等待设备的任何未完成的操作int (*flush) (struct file *, fl_owner_t id);/用来关闭设备int (*release) (struct inode *, struct file *);/用来刷新待处理的数据int (*fsync) (struct file *, struct dentry *, int datasync);/fsync的异步版本int (*aio_fsync) (struct kiocb *, int datasync);/通知设备FASYNC标志的改变int (*fasync) (
12、int, struct file *, int);/用来实现文件加锁,通常设备文件不需要实现此函数int (*lock) (struct file *, int, struct file_lock *);file_operations主要的函数 llseek()函数用于改变文件中的读写位置,并将新位置返回。 open()函数负责打开设备和初始化I/O。 release()函数负责释放设备占用的内存并关闭设备。 read()函数用来从设备中读取数据。 write()函数用来向设备上写入数据。 ioctl()函数实现对设备的控制。 mmap()函数将设备内存映射到进程的地址空间。若 aio_rea
13、d()和aio_write()函数分别实现对设备进程异步的读写操作。fileLinux中的所有设备都是文件,在内核中使用file结构体来表示一个打开的文件。file结构体中的重要成员 fmode_t f_mode loff_t f_pos unsigned int f_flags const struct file_operations *f_op void *private_datainodeinode结构体是一个内核文件系统索引节点对象,它包含了内核在操作文件或目录时所需要的全部信息。在内核中inode结构体用来表示文件,它与表示打开文件的file结构体的区别是,同个文件可能会有多个打开文
14、件,因此一个inode结构体可能会对应着多个file结构体。inode对于字符设备驱动来说,需要关心的是如何从inode结构体中获取设备号。与此相关的两个成员分别是: dev_t i_rdev 对于设备文件而言,此成员包含实际的设备号。 struct cdev *i_cdev 字符设备在内核中是用cdev结构来表示的。此成员是指向cdev结构的指针。inode内核开发者提供了两个函数来从inode对象中获取设备号,它们的定义如下:static inline unsigned iminor(const struct inode *inode) return MINOR(inode-i_rdev)
15、;static inline unsigned imajor(const struct inode *inode) return MAJOR(inode-i_rdev); 字符字符设备注册和注销设备注册和注销字符设备初始化 void cdev_init(struct cdev *, const struct file_operations *);字符设备注册 struct cdev *cdev_alloc(void);字符设备添加 void cdev_add(struct cdev *, dev_t, unsigned);字符设备删除 void cdev_del(struct cdev *);
16、方法一:struct cdev *my_cdev = cdev_alloc();my_cdev-owner = THIS_MODULE;my_cdev-ops = &fops;方法二:struct cdev my_cdev;cdev_init(&my_cdev, &fops);my_cdev.owner = THIS_MODULE;3、GPIO概述概述GPIO接口利用工业标准I22C、SMBus或SPI接口简化了I/O接口的扩展。当微控制器或芯片组没有足够的I/O端口,或当系统需要使用远程串行通信或控制时,GPIO接口能够提供额外的控制和监视功能。GPIO接口一般至少会有两个寄存器,即控制寄存
展开阅读全文