当前位置:首页 > 日记 > 正文

编写Linux设备驱动程序

编写Linux设备驱动程序

序言    Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少,只能依赖kernel中的函数,有些常用的操作要自己来编写,而且调试也不方便。本人这几周来为实验室自行研制的一块多媒体卡编制了驱动程序,获得了一些经验,愿与Linux fans共享,有不当之处,请予指正。    以下的一些文字主要来源于khg,johnsonm的Write linux device driver,Brennan’s Guide to Inline Assembly,The Linux A-Z,还有清华BBS上的有关device driver的一些资料。 这些资料有的已经过时,有的还有一些错误,我依据自己的试验结果进行了修正。    一、Linux device driver 的概念    系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件, 应用程序可以象操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它完成以下的功能:    1.对设备初始化和释放。    2.把数据从内核传送到硬件和从硬件读取数据。    3.读取应用程序传送给设备文件的数据和回送应用程序请求的数据。    4.检测和处理设备出现的错误。    在Linux操作系统下有两类主要的设备文件类型,一种是字符设备,另一种是块设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接着发生了,块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I/O操作。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。    已经提到,用户进程是通过设备文件来与实际的硬件打交道。每个设备文件都都有其文件属性(c/b),表示是字符设备还蔤强樯璞?另外每个文件都有两个设备号,第一个是主设备号,标识驱动程序,第二个是从设备号,标识使用同一个设备驱动程序的不同的硬件设备,比如有两个软盘,就可以用从设备号来区分他们。设备文件的的主设备号必须与设备驱动程序在登记时申请的主设备号一致,否则用户进程将无法访问到驱动程序。    最后必须提到的是,在用户进程调用驱动程序时,系统进入核心态,这时不再是抢先式调度。也就是说,系统必须在你的驱动程序的子函数返回后才能进行其他的工作。如果你的驱动程序陷入死循环,不幸的是你只有重新启动机器了,然后就是漫长的fsck.//hehe    读/写时,它首先察看缓冲区的内容,如果缓冲区的数据    如何编写Linux操作系统下的设备驱动程序    二、实例剖析    我们来写一个最简单的字符设备驱动程序。虽然它什么也不做,但是通过它可以了解Linux的设备驱动程序的工作原理。把下面的C代码输入机器,你就会获得一个真正的设备驱动程序。不过我的kernel是2.0.34,在低版本的kernel上可能会出现问题,我还没测试过。//xixi    #define __NO_VERSION__    #include <linux/modules.h>    #include <linux/version.h>    char kernel_version [] = UTS_RELEASE;    这一段定义了一些版本信息,虽然用处不是很大,但也必不可少。Johnsonm说所有的驱动程序的开头都要包含<linux/config.h>,但我看倒是未必。

由于用户进程是通过设备文件同硬件打交道,对设备文件的操作方式不外乎就是一些系统调用,如 open,read,write,close…, 注意,不是fopen, fread,但是如何把系统调用和驱动程序关联起来呢?这需要了解一个非常关键的数据结构:    struct file_operations {    int (*seek) (struct inode * ,struct file *, off_t ,int);    int (*read) (struct inode * ,struct file *, char ,int);    int (*write) (struct inode * ,struct file *, off_t ,int);    int (*readdir) (struct inode * ,struct file *, struct dirent * ,int);    int (*select) (struct inode * ,struct file *, int ,select_table *);    int (*ioctl) (struct inode * ,struct file *, unsined int ,unsigned long);    int (*mmap) (struct inode * ,struct file *, struct vm_area_struct *);    int (*open) (struct inode * ,struct file *);    int (*release) (struct inode * ,struct file *);    int (*fsync) (struct inode * ,struct file *);    int (*fasync) (struct inode * ,struct file *,int);    int (*check_media_change) (struct inode * ,struct file *);    int (*revalidate) (dev_t dev);    }    这个结构的每一个成员的名字都对应着一个系统调用。用户进程利用系统调用在对设备文件进行诸如read/write操作时,系统调用通过设备文件的主设备号找到相应的设备驱动程序,然后读取这个数据结构相应的函数指针,接着把控制权交给该函数。这是linux的设备驱动程序工作的基本原理。既然是这样,则编写设备驱动程序的主要工作就是编写子函数,并填充file_operations的各个域。    相当简单,不是吗?    下面就开始写子程序。    #include <linux/types.h>    #include <linux/fs.h>    #include <linux/mm.h>    #include <linux/errno.h>    #include <asm/segment.h>    unsigned int test_major = 0;    static int read_test(struct inode *node,struct file *file,    char *buf,int count)    {    int left;    if (verify_area(VERIFY_WRITE,buf,count) == -EFAULT )    return -EFAULT;    for(left = count ; left > 0 ; left--)    {    __put_user(1,buf,1);    buf++;    }    return count;    }    这个函数是为read调用准备的。当调用read时,read_test()被调用,它把用户的缓冲区全部写1.buf 是read调用的一个参数。它是用户进程空间的一个地址。但是在read_test被调用时,系统进入核心态。所以不能使用buf这个地址,必须用__put_user(),这是kernel提供的一个函数,用于向用户传送数据。另外还有很多类似功能的函数。请参考。在向用户空间拷贝数据之前,必须验证buf是否可用。    这就用到函数verify_area.    static int write_tibet(struct inode *inode,struct file *file,    const char *buf,int count)    {    return count;    }    static int open_tibet(struct inode *inode,struct file *file )    {    MOD_INC_USE_COUNT;    return 0;    }    static void release_tibet(struct inode *inode,struct file *file )    {    MOD_DEC_USE_COUNT;    }    这几个函数都是空操作。实际调用发生时什么也不做,他们仅仅为下面的结构提供函数指针。    struct file_operations test_fops = {    NULL,    read_test,    write_test,    NULL, /* test_readdir */    NULL,    NULL, /* test_ioctl */    NULL, /* test_mmap */    open_test,    release_test, NULL, /* test_fsync */    NULL, /* test_fasync */    /* nothing more, fill with NULLs */    };    设备驱动程序的主体可以说是写好了。现在要把驱动程序嵌

相关文章

Apache之AllowOverride参数详解

Apache之AllowOverride参数详解

参数详解,电脑软件,Apache,AllowOverride,通常利用Apache的rewrite模块对 URL 进行重写的时候, rewrite规则会写在 .htaccess 文件里。但要使 apache 能够正常的读取.htaccess 文件的内容,就必须对.htaccess 所在目录进行配置。从安全性考虑,…

win7怎么激活

win7怎么激活

激活,电脑软件,电脑开机后壁纸变成黑色,右下角提示此windows副本不是正版,这是因为win7系统没有激活造成的。下面小编教大家如何解决。方法一:1.打开win7的开始菜单,点击&ldquo;搜索程序和文件&rdquo;,输入&ldquo;cmd&rdquo;并按键盘回车。2.这…

Bootstrap Scrollspy源码学习

Bootstrap Scrollspy源码学习

学习,源码,电脑软件,Bootstrap,Scrollspy,本文实例为大家分享了Bootstrap Scrollspy插件的具体代码,供大家参考,具体内容如下导航栏Scrollspy例子<!-- The scrollable area --><body data-spy="scroll" data-target=".navbar" data-offse…

浅谈Vue父子组件和非父子组件传值

浅谈Vue父子组件和非父子组件传值

组件,传值,父子,浅谈,电脑软件,本文介绍了浅谈Vue父子组件和非父子组件传值问题,分享给大家,具体如下:1.如何创建组件1.新建一个组件,如:在goods文件夹下新建goodsList.vue<template> <div class='tmpl'> goodsList组件 </div></template…

Linux系统下像windows系统下修改ho

Linux系统下像windows系统下修改ho

系统,文件,修改,绑定域名,地址,例如:localhost 127.0.0.1 127.0.0.1 当访问 时,实际上是访问127.0.0.1 这样的用处是用域名调试本地程序。在Windows下只需要修改:C:\Windows\System32\drivers\etc\hosts\hosts 文件即可(用记事本打…

一个Js文件函数中调用另一个Js文件

一个Js文件函数中调用另一个Js文件

文件,函数,方法,调用,演示,我们知道,在html中,利用<script language="javascript" type="text/javascript" src="./script.js"></script>引入的两个js是不可以相互调用的。那么该如何解决呢?当然,你可以将代码通通copy过来,也许你并不喜欢…

PHP实现腾讯与百度坐标转换

PHP实现腾讯与百度坐标转换

坐标转换,百度,腾讯,电脑软件,PHP,废话不多说,直接上代码public function coordinate_switch($a,$b){//百度转腾讯坐标转换 $x = (double)$b - 0.0065; $y = (double)$a - 0.006; $x_pi = 3.14159265358979324; $z = sqrt($x * $x+$y * …

如何在Word2003文档修改修改添加备

如何在Word2003文档修改修改添加备

修改,文档,备忘录,如何在,电脑软件,一般来说,评审会修改原文件的内容,你可以添加注释的修改的地方。这是修订后的功能的话,这主要是因为我们之前的话使方便。以下是小编辑给你带来了关于修订内容在帮助你希望添加一个文件格式。 内容之前修改…

php实现中文转数字

php实现中文转数字

中文,转数,电脑软件,php,分享一个辅助函数,使用php尽可能识别出字符串中的数字,先上代码function checkNatInt($str) { $map = array( '一' => '1','二' => '2','三' => '3','四' => '4','五' => '5','六' => '6…

cdr中想要制作艺术蜡笔效果的?

cdr中想要制作艺术蜡笔效果的?

蜡笔,效果,艺术,电脑软件,cdr,cdr中想要制作一个蜡笔画效果的图,该怎么给图片制作蜡笔效果呢?下面我们就来看看详细的教程。软件名称:CorelDraw x6 (Cdr x6) 官方简体中文破解版(32位)安装图文教程、破解注册方法软件大小:更新时间:2014-08-271、…

PS淘宝金属皮带扣图形美化过程共享

PS淘宝金属皮带扣图形美化过程共享

淘宝,图形,过程,电脑软件,PS,版权:原作者JamesVin 感谢JamesVin 原有的经验分享! PS淘宝金属皮带扣的朋友照片修饰美化过程分享的整个过程,金属皮带扣的修饰和美化材料,包括抠图、分类、运动模糊、噪声+灯+面膜11部分,强调的是实用,初学者可能会…

JavaScript 网页中实现一个计算当

JavaScript 网页中实现一个计算当

网页,计算,倒数,还剩,当年,看到网上这个程序 发现了处错误这里改正了一下:function counter() { var date = new Date(); var year = date.getFullYear(); var date2 = new Date(year, 11, 30, 23, 59, 59); /*转换成秒*/ var tim…