经典 【操作系统实验】 实验六 设备驱动程序 RH5 2.6.18 + 2.6.32 内核

设备驱动程序

前言:
本文是基于Linux的设备驱动实验流程记录,涵盖了【字符设备驱动程序】以及【虚拟块设备驱动程序】。
本身尝试了Ubuntu16.04的4.4.49内核,但因为虚拟机问题还有本人能力问题最终放弃,然后尝试了RedHats系统的2.6.32版本内核。
实在是太香了!没有比老内核更适合引入该部分模块内容的了。
应某位小伙伴需求贴出RH6的链接,安装什么的应该不用教了[doge]
Red Hats 6.5 2.6.32
提取码: 1fg6
RedHat5 kernel2.6.18 下载链接(http://mirrors.sohu.com/RHEL/AS5U5/i386/rhel-server-5.5-i386-dvd.iso)(下载引擎打开)
一、 实验目的
1、 理解Linux设备驱动程序的基本知识
2、 掌握设备驱动程序的编写原则和过程
3、 实现一个基于主存的虚拟块设备驱动程序,并进行测试
二、实验原理
1.Linux设备驱动程序:
总体上说,编写linux设备驱动应该是linux内核编程中最难的部分,一般只有在全面熟悉了linux内核之后,并且在接口技术很扎实的情况下才能开始真正地开发设备的驱动。我们实验书上所做的设备驱动只局限于软件部分,即linux内核,并未真正涉及设备。
Linux下设备基本上分为三部分:字符设备、块设备、网络设备。其中网络设备是最复杂的一部分。
在linux下开发设备驱动基本上分为几个过程:

  1. 根据外设的接口协议编写相应的功能函数原型;
  2. 将得到的函数原型用linux的驱动程序接口封装起来;
  3. 将封装好的模块动态加入到linux内核中。
    以上步骤中第一步主要与设备的接口协议相关,后两步主要与操作系统相关。这里主要简单讨论一下后两步。
    以字符设备为例,操作系统要求驱动程序用相应得接口函数封装起来,接口函数为一个函数的集合,集合中包括了所有可能对该设备进行操作的动作,这个函数的集合用一个struct file_operations数据结构来表示:
  4. struct file_operations中的操作按如下顺序出现,除非注明,它们的返回0时表示成功,发生错误时返回一个负的错误编码:
  5. int (*lseek)(struct inode *, struct file *, off_t, int);方法lseek用来修改一个文件的当前读写位置,并将新位置做为(正的)返回值返回。出错时返回一个负的返回值。
  6. int (*read)(struct inode *, struct file *, char *, int);用来从设备中读取数据。当其为NULL指针时将引起read系统调用返回-EINVAL(“非法参数”)。函数返回一个非负值表示成功的读取了多少字节。
  7. int (*write)(struct inode *, struct file *, const char *, int);向设备发送数据。如果没有这个函数,write系统调用向调用程序返回一个-EINVAL。如果返回值非负,它就表示成功地写入的字节数。
  8. int (*readdir)(struct inode *, struct file *, void *, filldir_t);对于设备节点来说,这个字段应该为NULL;它仅用于目录。
  9. int (*select)(struct inode *, struct file *, int, select_table *);select一般用于程序询问设备是否可读和可写,或是否一个“异常”条件发生了。
  10. int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);系统调用ioctl提供一中调用设备相关命令的方法(如软盘的格式化一个磁道,这既不是读操作也不是写操作)。ioctl系统调用将返回-EINVAL。当调用成功时,返回给调用程序一个非负返回值。
  11. int (*mmap)(struct inode *, struct file *, struct vm_area_struct *);mmap用来将设备内存映射到进程内存中。如果设备不支持这个方法,mmap系统调用将返回-ENODEV。
  12. int (*open)(struct inode *, struct file *);尽管这总是操作在设备节点上的第一个操作,然而并不要求驱动程序一定要声明这个方法。
  13. void (*release)(struct inode *, struct file *);当节点被关闭时调用这个操作。与open相仿,release也可以没有。
  14. int (*fsync)(struct inode *, struct file *);刷新设备。如果驱动程序不支持,fsync系统调用返回-EINVAL。
  15. int (*fasync)(struct inode *, struct file *, int);这个操作用来通知设备它的FASYNC标志的变化。
  16. int (*check_media_change)(kdev_t dev);check_media_change只用于块设备,尤其是象软盘这类可移动介质。
  17. int (*revalidate)(kdev_t dev);这是最后一项,与前面提到的那个方法一样,也只适用于块设备。revalidate与缓冲区高速。缓存有关。
    将设备的功能用以上函数封装之后,就形成了一个可以动态加入到linux内核中的模块,遵循一定的规则就可以动态地将新模块加入到正在运行中的内核中,或者从内核中删除不必要的模块。当模块加入后,无需重新启动系统,设备驱动程序就能工作起来。
    模块化编程的一个难点是内核版本的差异,即不同版本的内核其添加系统模块的具体方式不同。实验书上所介绍的方法只适用于2.2以前的内核,而2.4和2.6内核的方式又各有不同。

简单介绍一下2.6版本内核添加模块的方法:

a.编写内核模块文件,如
hello.c

#include <linux/init.h>
#include 
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值