国语自产精品视频在线看:您身边最放心的安全下载站! 最新软件|热门排行|软件分类|软件专题|厂商大全

国语自产精品视频在线看

技术教程
您的位置:首页服务器类Linux服务器 → 编写Linux设备驱动程序

编写Linux设备驱动程序

我要评论 2011/03/29 12:38:13 来源:国语自产精品视频在线看 编辑:downcc.com [ ] 评论:0 点击:220次

序【xù】言
    Linux是【shì】🎯Unix操作【cāo zuò】📁系统的【de】一【yī】⬅种变种😣,在【zài】🍁Linux下编写【xiě】🔜驱动程【qū dòng chéng】🏖序【xù】的【de】➿原理和思想完【sī xiǎng wán】全类似于其他【yú qí tā】的【de】➿Unix系统,但它【dàn tā】dos或window环【huán】境下的驱动【de qū dòng】🍉程序有【chéng xù yǒu】很大的【hěn dà de】➿区【qū】🤸别。在【zài】🍁Linux环【huán】境下设计驱【shè jì qū】动程【dòng chéng】🏖序【xù】,思想简洁【jié】,操作【cāo zuò】📁方便🌦,功能也很强大🍿,但是【shì】🎯支持函【zhī chí hán】数少,只能依赖【lài】👸kernel中的【zhōng de】➿函数【hán shù】,有些常用的【de】➿操作【cāo zuò】📁要自己来编【lái biān】🏢写【xiě】📖,而且调试也不【shì yě bú】方便🌦。本人这【běn rén zhè】几周来【jǐ zhōu lái】为实验【wéi shí yàn】🍹室自行🤴研制的【de】➿一块多【yī kuài duō】媒体卡【méi tǐ kǎ】🦓编制了【le】😘驱动程【qū dòng chéng】🏖序【xù】,获得了【le】一【yī】些经🍃验,愿与Linux fans共享【gòng xiǎng】,有不当❤之处【zhī chù】,请予指【qǐng yǔ zhǐ】🌸正😗。
    以下的【yǐ xià de】一【yī】些⛎文字主要来源于khg,johnsonm的【de】➿Write linux device driver,Brennan’s Guide to Inline Assembly,The Linux A-Z,还有清【hái yǒu qīng】华BBS上的有【shàng de yǒu】👜关device driver的一些【de yī xiē】⛎资料。 这些资料有的【liào yǒu de】➿已经过🕳时,有的【de】➿还有一【yī】些错误【xiē cuò wù】📒,我依据自己的【de】➿试验结果进行【guǒ jìn háng】了【le】修正🌽。
    一【yī】、Linux device driver 的【de】概念🔓
    系统调🌻用是【shì】🎯操作【cāo zuò】📁系统内【xì tǒng nèi】核和【hé hé】💦应用程序【xù】之间的【zhī jiān de】接口【jiē kǒu】🕶,设备驱【qū】👠动程序【dòng chéng xù】🤷是【shì】🎯操作【cāo zuò】📁系统内【xì tǒng nèi】核和【hé hé】💦机器硬【jī qì yìng】件🦂之间的【zhī jiān de】接口【jiē kǒu】🕶。设备驱【qū】👠动程序【dòng chéng xù】🤷为应用【wéi yīng yòng】🆖程序【xù】屏蔽了【le】硬件【yìng jiàn】🦂的【de】➿细节【xì jiē】,这样在【zài】🍁应用程序看来【xù kàn lái】,硬件【yìng jiàn】🦂设备只是【shì】🎯一【yī】个设备文【shè bèi wén】件😉, 应用程序可以【xù kě yǐ】💨象操作【cāo zuò】📁普通文【pǔ tōng wén】件一【yī】样对硬件【yìng jiàn】🤗设备进🔵行操作【háng cāo zuò】📁。设备驱【qū】👠动程序【dòng chéng xù】🤷是内核【shì nèi hé】🍤的【de】➿一【yī】部分,它完成【tā wán chéng】以下的【yǐ xià de】➿功能:
    1.对设备【duì shè bèi】初始化【chū shǐ huà】和释放。
    2.把数据【shù jù】👇从内核传送到【chuán sòng dào】硬件【yìng jiàn】🦂和从硬件【yìng jiàn】🦂读【dú】🆘取数据【qǔ shù jù】🎌。
    3.读【dú】🆘取应用程序【xù】传送给😽设备文【shè bèi wén】件😉的【de】➿数据【shù jù】🎌和回送应用程序请求【xù qǐng qiú】的【de】➿数据【shù jù】🎌。
    4.检测和处理设【chù lǐ shè】备出现【bèi chū xiàn】的错误【de cuò wù】🔞。
    在【zài】🍁Linux操作【cāo zuò】📁系统下有🕘两类主要的【de】➿设备文【shè bèi wén】件😉类型,一【yī】种是【shì】😍字符设🔦备,另一【yī】种是【shì】😍块设备【kuài shè bèi】。字符设🔦备和块🧚设备的【de】🔶主要区【zhǔ yào qū】🦂别是【shì】🎯:在【zài】🍁对字符设🔦备发出读【dú】🛳/写【xiě】📖请求时【qǐng qiú shí】,实际的【jì de】➿硬件【yìng jiàn】🦂I/O一般就【yī bān jiù】紧接着发生了【le】📶,块设备【kuài shè bèi】则不然,它利用一块系【yī kuài xì】统内存作缓冲区【qū】🤸,当用户🛶进程对【jìn chéng duì】设备请求能满【qiú néng mǎn】足用户的【de】➿要求,就返回请求的【de】➿数据【shù jù】🎌,如果不🐍能,就调用【jiù diào yòng】🦒请求函🕑数来进🏳行实际的【jì de】➿I/O操作【cāo zuò】📁。块设备【kuài shè bèi】是【shì】🎯主要针对磁盘【duì cí pán】等慢⭐速设备【sù shè bèi】♑设计的【de】➿,以免耗费过多📒的【de】➿CPU时间来【shí jiān lái】等待🎃。
    已经提【yǐ jīng tí】到【dào】,用户进🌊程是通【chéng shì tōng】🦅过设备文【shè bèi wén】件😉来与实际的【jì de】➿硬件【yìng jiàn】🦂打交道🌎。每个设备文【shè bèi wén】件😉都都有【dōu dōu yǒu】其文件【qí wén jiàn】⛏属性(c/b),表示是【shì】🎯字符设🔦备还蔤💗强樯璞【qiáng qiáng pú】?另外每个文件都有两个设备号🐍,第一个【dì yī gè】是【shì】🎯主设备号🐍,标识驱【qū】➖动程序【dòng chéng xù】🤷,第二【èr】个🤾是【shì】🎯从设备号🐍,标识使用同一【yī】🏊个设备驱【qū】👠动程序【dòng chéng xù】🤷的【de】➿不同的【de】➿硬件【yìng jiàn】🦂设备,比如有两个软盘💬,就可以用从设备号来【bèi hào lái】🥖区【qū】分他🤯们🔫。设备文【shè bèi wén】件😉的【de】➿的【de】➿主设备号🐍必🤲须与设备🔖驱动程【qū dòng chéng】🏖序【xù】在【zài】登🈴记时申请的【de】➿主设备号🐍一【yī】致,否则用🚤户进程🖲将无法【jiāng wú fǎ】🍉访问到【dào】驱动程【qū dòng chéng】🏖序【xù】。
    最后必【zuì hòu bì】🤲须提到【xū tí dào】的【de】是【shì】🤪,在【zài】🍁用户进🌊程调用驱动程【qū dòng chéng】🏖序时【xù shí】,系统进入核心🔸态【tài】🔒,这时不再是【shì】🎯抢先式调🤹度😮。也就是【shì】🎯说🍢,系统必🤲须在【zài】🍁你的驱动【de qū dòng】🍉程序的【chéng xù de】➿子函数【zǐ hán shù】返回后【fǎn huí hòu】才能进🍅行其他🏐的【de】➿工作【gōng zuò】。如果你【rú guǒ nǐ】的驱动【de qū dòng】🍉程序【xù】陷入死循🚞环【huán】,不幸的【de】是【shì】🤪你只有重新启动机器了【le】,然后就🗑是【shì】🎯漫长的【màn zhǎng de】➿fsck.//hehe
    读【dú】🆘/写【xiě】📖时,它首先【tā shǒu xiān】🍊察看缓🎋冲区的【chōng qū de】✏内容,如果缓冲区的【chōng qū de】✏数据【shù jù】🎌
    如何编🚺写【xiě】📖Linux操作【cāo zuò】📁系统下的【de】➿设备驱【qū】👠动程序【dòng chéng xù】🤷
    二【èr】、实例剖析
    我们🔫来写【xiě】一【yī】个🎊最简单的【de】➿字符设🔦备驱动程【qū dòng chéng】🏖序【xù】。虽然它♓什么也【shí me yě】不做,但是【shì】🎯通过它可以了【le】解Linux的【de】➿设备驱【qū】👠动程序【dòng chéng xù】🤷的【de】➿工作【gōng zuò】原理。把下面【bǎ xià miàn】🐭的【de】➿C代码输入机器,你就会获得一【yī】个真正😍的【de】➿设备驱【qū】👠动程序【dòng chéng xù】🤷。不过我的【de】➿kernel是【shì】🎯2.0.34,在【zài】🍁低版本【dī bǎn běn】的【de】👁kernel上可能会出现🛅问题,我还没【wǒ hái méi】🗯测试过。//xixi
    #define __NO_VERSION__
    #include <linux/modules.h>
    #include <linux/version.h>
    char kernel_version [] = UTS_RELEASE;
    这一【yī】段定义了【le】一【yī】些版本信息,虽然用处不是【chù bú shì】🎯很大,但也必【dàn yě bì】🤲不可少【bú kě shǎo】。Johnsonm说🍢所有的驱动【de qū dòng】🍉程序的【chéng xù de】➿开头都🔡要包含【yào bāo hán】<linux/config.h>,但我看【dàn wǒ kàn】倒是【shì】🎯未必【wèi bì】🤲。

由于用【yóu yú yòng】户进【hù jìn】✂程是通过【guò】🚟设备文【shè bèi wén】📗件同硬【jiàn tóng yìng】🔫件打交【jiàn dǎ jiāo】道⌚,对设备【duì shè bèi】文【wén】📗件的操【jiàn de cāo】作方式不外乎就是一【jiù shì yī】些系👃统调用【tǒng diào yòng】,如【rú】 open,read,write,close…, 注意【zhù yì】,不是⛰fopen, fread,但是如【dàn shì rú】🌞何把系统调【xì tǒng diào】用【yòng】和驱动【qū dòng】程序关联起来呢👿?这需要了解一个非常关键的【de】数【shù】🐶据结构:
    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);
    }
    这个结🐇构的每【gòu de měi】一个成【yī gè chéng】🤜员的【de】名字都对📍应着一【yīng zhe yī】个系统【gè xì tǒng】🕳调用【yòng】。用户进【yòng hù jìn】✂程利用【yòng】🚚系统调【xì tǒng diào】用在对【yòng zài duì】设备文【shè bèi wén】📗件进行😾诸如【rú】🎥read/write操作时【shí】✏,系统调【xì tǒng diào】用【yòng】通过【guò】🚪设备文【shè bèi wén】📗件的【de】主设备号找到相🤟应的设【yīng de shè】备驱动【qū dòng】🎿程序,然后读【rán hòu dú】👲取这个数【shù】🐶据结构相应的【de】函数【shù】指🍻针【zhēn】,接着把控制权【kòng zhì quán】交给该【jiāo gěi gāi】函数【shù】🐶。这是linux的【de】设备驱【shè bèi qū】动【dòng】🎿程序工作的基【zuò de jī】本原理🏦。既然是这样🎽,则编写【zé biān xiě】设备驱【shè bèi qū】动【dòng】🎿程序的【de】主要工作就是编写🚊子函数【shù】🐶,并填充file_operations的【de】各个域。
    相当简单,不是⛰吗?
    下面就开始写子程序。
    #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;
    }
    这个函数是为【shù shì wéi】🌍read调用【yòng】准备的【de】🐉。当调用【yòng】read时【shí】🐄,read_test()被调用【bèi diào yòng】🛂,它把用【yòng】户的【de】缓冲区全💒部写【bù xiě】🎇1.buf 是read调用【yòng】的【de】一个参【yī gè cān】数【shù】🐶。它是用户进【yòng hù jìn】✂程空间的【de】👣一个地【yī gè dì】🕰址【zhǐ】。但是在【dàn shì zài】read_test被调用【bèi diào yòng】🛂时【shí】🐄,系统进入核心【rù hé xīn】态。所以不【suǒ yǐ bú】🚉能使用【yòng】🚱buf这个地址【zhǐ】,必须用【yòng】__put_user(),这是kernel提供的【de】一个函🛬数【shù】🐶,用【yòng】于向用户传【yòng hù chuán】送数【shù】🐶据。另外还有很多【yǒu hěn duō】类似功🐥能的函【néng de hán】💈数【shù】🐶。请参考🏖。在向用【zài xiàng yòng】📞户空间拷贝数【shù】🐶据之前,必须验【bì xū yàn】证【zhèng】buf是否可用【yòng】。
    这就用【zhè jiù yòng】到函数【shù】🐶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;
    }
    这几个函数【shù】都🦑是空操🐳作。实际调用【yòng】发生时【shí】什么👶也不做🥉,他们仅【tā men jǐn】🦏仅为下【jǐn wéi xià】面的【de】结构提供🎰函数【shù】指🍻针【zhēn】。
    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 */
    };
    设备驱【shè bèi qū】动【dòng】🎿程序的【de】主体可以说🛃是写好🐓了。现在要把驱动【qū dòng】程序嵌🚩

关键词:Linux,驱动【qū dòng】程序

阅读本文后您有什么感想? 已有 人给出评价!

  • 1 欢迎喜欢
  • 1 白痴
  • 1 拜托
  • 1 哇
  • 1 加油
  • 1 鄙视