欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    2022年第一个驱动程序 .pdf

    • 资源ID:26492610       资源大小:752.40KB        全文页数:8页
    • 资源格式: PDF        下载积分:4.3金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要4.3金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    2022年第一个驱动程序 .pdf

    Linux 下第一个驱动程序因为在 Ubuntu 环境下写的文章和做的实验,没有安装linux 下比较好用的截图工具,所以没有附带太多截屏,还望海涵,不过该描述的都到位了,希望对你有用。曾经还一直处于应用程序开发的我,以为驱动开发者是那么的厉害,以为只有牛人才能走到这一步,随着知识的积累,发现并非如此,驱动开发并不像想象中那么特别,俗话说术业有专攻,开发者只是使用的工具不同,且从事的领域不同,产品不同罢了。只要能作出好的产品,你就是一个 ” 牛人 ” 。从这里开始进行系统化的驱动学习,主线是Linux 设备驱动开发详解,之前大致看过这本书,起初感觉有些晦涩,但看了两本内核的书籍以后,重新回来读起来就比较顺流了,一口气读了好几章 (主要是前几章是知识介绍性文章)。所以这里顺便推荐两本内核的书籍:Linux 内核设计与实现,我看的是第二版,写的非常棒,简单易懂,要在介绍内核原理与实现机制,广度到了,深度不够,所以最好还得配合下边这本书一块儿看。Understanding Linux kernel 深入理解 linux 内核,这本书的第三版是基于2.6内核的, 06 年出版。我看的是英文原版的,所以看得速度比较满,不过正好和Linux 设备驱动开发详解对接上了,刚看过Understanding Linux kernel中的同步异步,应该是第五章那里,然后 Linux 设备驱动开发详解就在第七章也讲到了,这样,可能那么多机制:锁,读写锁,顺序锁,信号量,读写信号量一下出来这么多东西的话有些接受不了,但如果你之前看了 Linux 内核设计与实现后,最起码不会感觉恐慌,其实学习新的知识就是这样,一回生两回熟,再难理解的东西,功夫到了,也就理解了。好的,开始第一个驱动程序的学习,实例来自Linux 设备驱动开发详解,这里是创建了一个虚拟的字符设备globalmem,也就是一片内核空间的内存区域,来实现内核空间和用户空间的信息传递。 (确实,我举不出来比这更好的例子来作第一个例子了,不过请相信,哪怕就是这个例子也是我一个字母一个字母敲出来的,并未直接取材自隋书的源码,主要是看我的注释,和我遇到的问题以及解决它的全过程,成功者找方法,失败者找借口!呵呵) 不废话,上代码,别心急,看注释。下边是驱动的源码,附上了详尽的注释:globalmem.c * #include #include #include #include #include #include #include #include #include #include #define GLOBALMEM_SIZE 0 x1000 /*4k 的空间 */ #define MEM_CLEAR 0 x1 /*清空全局内存 */ #define GLOBALMEM_MAJOR 250 /* 预设的主设备号*/ static int globalmem_major = GLOBALMEM_MAJOR; /*用面向对象思想对cdev重新封装,以便于方便我们的操作*/ struct globalmem_dev 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 8 页 - - - - - - - - - struct cdev cdev; unsigned char memGLOBALMEM_SIZE; ; struct globalmem_dev *globalmem_devp; /*声明一个全局的设备结构体*/ /*用来注册到file_operations 结构中 open */ int globalmem_open(struct inode *inode,struct file *filp) filp-private_data = globalmem_devp; /* 当有多个同类设备时,用私有变量访问很有必要也很方便*/ return 0; /*用来注册到file_operations 结构中 release */ int globalmem_release(struct inode *inode,struct file *filp) return 0; /*用来注册到file_operations 结构中 ioctl */ static int globalmem_ioctl(struct inode *inodep,struct file *filp,unsigned int cmd,unsigned long arg) struct globalmem_dev *dev = filp-private_data; /*从私有数据获取设备结构体指针*/ switch (cmd) case MEM_CLEAR: memset(dev-mem,0,GLOBALMEM_SIZE); printk(KERN_INFOglobalmem is set to zeron); break; default: return -EINV AL; return 0; /*用来注册到file_operations 结构中 read */ static ssize_t globalmem_read(struct file *filp,char _user *buf,size_t size,loff_t *ppos) unsigned long p = *ppos; /*获取到当前全局内存的*/ unsigned int count = size; /*获取到要读取数据的大小*/ int ret = 0; /*用来记录返回值 */ struct globalmem_dev *dev = filp-private_data; /*从私有变量获取到设备结构体指针*/ /*分析和获取有效的读长度,就是看给的要读取的长度是否合法*/ if(p=GLOBALMEM_SIZE) return 0; if(countGLOBALMEM_SIZE-p) /*如果要读取的量比剩余的还多,只给它可读到的量*/ count=GLOBALMEM_SIZE-p; /*一切就绪后就开始往用户空间读了,这里的读指的是用户空间的读,就是说从内核拷贝到用户空间,* 因为内核是万能的有着所有的权限,主动权在于它,并不是说用户想读就可以读的,因为该空间是在内核状态下分配出来的*/ if(copy_to_user(buf,(void*)(dev-mem+p),count) /*从 mem的偏移量p 处拷贝 count 个数据到 buf 所指区 */ ret = -EFAULT; /* 拷贝失败,返回 -EFAULT*/ else /* 拷贝成功,返回重新拷贝的数据量并重新计算的偏移量*/ *ppos+=count; ret = count; printk(KERN_INFO read %u bytes(s) from %lun,count,p); return ret; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 8 页 - - - - - - - - - /*用来注册到file_operations 结构中 write */ static ssize_t globalmem_write(struct file *filp,char _user *buf,size_t size,loff_t *ppos) unsigned long p = *ppos; /*获取到当前全局内存的*/ unsigned int count = size; /*获取到要读取数据的大小*/ int ret = 0; /*用来记录返回值 */ struct globalmem_dev *dev = filp-private_data; /*从私有变量获取到设备结构体指针*/ /*分析和获取有效的写长度,就是看给的要写的长度是否合法*/ if(p=GLOBALMEM_SIZE) return 0; if(countGLOBALMEM_SIZE-p) /*如果要读取的量比剩余的还多,只给它可读到的量*/ count=GLOBALMEM_SIZE-p; /*一切就绪后就开始往共享空间里写了,这里的写指的就是说从用户空间拷贝到内核,* 因为内核是万能的有着所有的权限,主动权在于它,并不是说用户想写就可以写的,因为该空间是在内核状态下分配出来的*/ if(copy_from_user(dev-mem+p,buf,count) /*往 mem 的偏移量 p 处拷贝 count 个数据 (从 buf 所指区 )*/ ret = -EFAULT; /* 拷贝失败,返回 -EFAULT*/ else /* 拷贝成功,返回重新拷贝的数据量并重新计算的偏移量*/ *ppos+=count; ret = count; printk(KERN_INFO read %u bytes(s) from %lun,count,p); return ret; /*seek 文件定位函数 */ static loff_t globalmem_llseek(struct file *filp,loff_t offset,int orig) loff_t ret = 0; switch (orig) case 0: /*相对于文件开始位置*/ if(offsetGLOBALMEM_SIZE) ret = -EINVAL; break; filp-f_pos=(unsigned int)offset; ret=filp-f_pos; break; case 1: /*相对于文件当前位置*/ if(filp-f_pos+offset)GLOBALMEM_SIZE) ret = -EINVAL; break; if(filp-f_pos+offset)f_pos+=offset; ret=filp-f_pos; break; default: ret = -EINVAL; break; return ret; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 8 页 - - - - - - - - - /*文件操作结构体*/ static const struct file_operations globalmem_fops= .owner = THIS_MODULE, .llseek = globalmem_llseek, .read = globalmem_read, .write = globalmem_write, .ioctl = globalmem_ioctl, .open = globalmem_open, .release = globalmem_release, ; /*对设备进行初始化的函数*/ static void globalmem_setup_cdev(struct globalmem_dev *dev,int index) int err,devno = MKDEV(globalmem_major,index); /*MKDEV宏来生成设备号主设备号占12 位,从设备号占20 位*/ cdev_init(&dev-cdev,&globalmem_fops); dev-cdev.owner = THIS_MODULE; err = cdev_add(&dev-cdev,devno,1); if(err) printk(KERN_NOTICE ERROR %d adding globalmem %d,err,index); /*模块相关函数 */ /*为了便于开发和派错,建议上来先定义这些模块相关的初始化和卸载函数,你完全可以* 只做一个空的函数实现,意在每写一个功能函数就编译(make)一次,这样会很有利于开发的*/ /*驱动加载函数 */ int globalmem_init(void) int result; dev_t devno =MKDEV(globalmem_major,0); /*申请设备号 */ if(globalmem_major) result = register_chrdev_region(devno,1,globalmem); else /* 动态申请 */ result = alloc_chrdev_region(&devno,0,1,globalmem); globalmem_major = MAJOR(devno); if(resultcdev); /*注销掉设备 */ kfree(globalmem_devp); /* 释放掉分配的内存,好借好还再借不难*/ unregister_chrdev_region(MKDEV(globalmem_major,0),1); /*释放设备号 */ MODULE_AUTHOR(Jun ); MODULE_LICENSE(DUAL BSD/GPL); module_init(globalmem_init); module_exit(globalmem_exit); Makefile 的写法和前面一篇文章的helloworld 的模块的 Makefile 写法一致,换个模块的名字而已,这里是:obj-m += globalmem.o # XXX.o 对应于你的XXX.c 同时也是你的模块名称all: make -C /usr/src/linux-headers-2.6.32-27-generic M=$(shell pwd) modules # 这里通过 uname -r 命令获取系统信息,同时拼装出内核源码树的路径;# pwd 获取当前文件夹,这就要求着在你进行make的时候要在源码目录下。clean: make -C /usr/src/linux-headers-2.6.32-27-generic M=$(shell pwd) clean # 原理同上准备好后开始进行编译,就是make一下就 OK ;make时又遇到了这样的问题:make: Nothing to be done for all. Make clearn 时也会出现:make: Nothing to be done for clearn. 网上说的都是一编译好了,只是没有修改源文件,所以没有进行再编译(我知道这也是 make存在的理由,它的一方面功能就是这样的,避免重复编译未修改的文件),但显示是它确实不存在这个问题,我小纠结了一下,并且也没有其他任何编译时的报错提示。为了做测试,我又试着编译之前的helloworld 的模块,终于报错了,哈哈哈。问题在于,make中的make -C /usr/src/linux-headers-$(shell uname -r) M=$(shell pwd) modules ,该命令是动态的通过 shell命令的 uname来获取当前内核源码路径,并进行连接编译驱动的。而我下载并构建的内核是: 2.6.32-30-generic,而此时系统装载的是 (也就是 uname r 命令得到的内核版本):2.6.30-27-generic , 而该版本的内核源码树我已经手动删除,所以我的源码路径和通过uname -r组装出来的是不一致的,所以我把Makefile 中的命令手动修改成了:make -C /usr/src/linux-headers- 2.6.32-30-generic M=$(shell pwd) modules ,直接指定路径(这样的可维护性下降了,不过我们的工程太小,可以忽略这个问题)。OK ,try again,make 通过了,目录下编译出来了那群你梦寐以求想看到的文件们,他们这时显得是如此的可爱。这里还要说的是,模块只是一种把自己的代码动态加载到内核的手段,这也就说明了为什么我的驱动模块的Makefile文件为何和helloworld模块的Makefile文件是一模一样的(确实,模块的名字是不一样的,你知道我是什么意思),所以对于驱动来说,模块就是一条小船,它把代码运载到了kernel所在的海域,作为一个载体把驱动的代码带到了内核空间,从而使得你在用户空间调用某些系统操作时,OS可以找到对应的代码来完成你的请求。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 8 页 - - - - - - - - - 好的,编译好了,就该装载并测试了。$ insmod globalmem.ko #“ Ubuntu下必要时记着加sudo,因为我已经开启了ubuntu的su”呵呵,又来错误了。看来又要成长了,要善待你碰到的没一个失败,毕竟她是成功他妈。装载时报错了:insmod: error inserting globalmem.ko: -1 Invalid module format 还是因为我系统现装载的内核和对模块进行编译的内核版本不一致造成的,所以,我得把在构建的内核源码树中版本较新的内核安装到系统中去才行。这里安装新内核的方法,可以借鉴这篇博文 (哈哈,我越来越爱西邮的学生了,如果你想考研或者招聘,西邮出来的做linux的都是非常棒的。额,作广告了,呵呵):http:/ our module ,try again。$ insmod globalmem.ko well done,weve already make it.好的,接下来在用户空间测试一下。驱动是针对设备而言的(虽然这里的设备并非是实实在在的,只是一片内存),而linux下的设备又都是抽象成文件来看待的(毕竟unix最早是从一个文件系统演变过来的,也就是这一壮举,使得驱动的开发容易多了,统一的抽象带来了非常大的方便)。所以我们要把这个设备文件创建出来。$ mknod /dev/globalmem c 250 0 #创建一个主设备号为250次设备号是0的字符设备文件globalmem到dev下。然后就可以开始测试了:$echo “ Hello jun” /dev/globalmem #写“hello jun”到设备提示:bash: /dev/globalmem: Permission denied 权限不够, ls -l 发现:crw-r-r- 1 root root 250, 0 Oct 20 15:47 /dev/globalmem 你要么用 sudo 来 echo ,要么把文件权限该一下,这个自由留给你了。呵呵$cat /dev/globalmem #显示设备文件的内容显示如下:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 8 页 - - - - - - - - - rootjun-desktop:/home/jun/driver/ch6# cat /dev/globalmem hello jun 好的,大功告成!后记说明:1、做驱动的话,建议可以在原生的linux环境下,其实也挺方便的。2、推荐一个 c/c+ 的 IDE 吧 Code:Blocks ,挺好用的集成开发环境,只是第一次用它就喜欢上了,不过和SCIM输入法稍有冲突,注释的时候要输入中文,如果中文文字删减时,会出现打不上中文的情况,要调成英文状态再调回中文状态才能继续。另外,它带有语句联想功能,当然是只支持用户空间c 函数库德联想,不支持kernel中的函数或结构。个人感觉要比Vi 用着来的有效率些,呵呵3、对于 echo 是“! ”的问题。截屏中可以看到,要输出! 还要进行转义字符转义。4、从文章可以看出,作者我确实够笨,每次记录都会碰见如此多的看似比较弱智的问题,好在找到了解决办法,详尽写实的记录比较符合本人博客的特色。5、编写和编译该驱动的环境并非前边文章介绍的虚拟机环境,是本机硬盘上的Ubuntu10.04,在我机器上有些时日了,忘了内核版本才凸显了上边遇到的很多问题, unlikely(你的开发过程中不会遇到类似的装载内核和编译内核不协调的情况 ); 不过你可能会在其他地方遇到,遇到是千万别说没见过而束手无策。6、提前把第一个驱动实验的记录过程发blog 了,驱动相关的知识还没有内容介名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 8 页 - - - - - - - - - 绍,可能和前边知识不太衔接,得花谢时间尽快补上。不过希望读者和我同步一起不断积累内核体系的相关知识,非常方便理解的。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 8 页 - - - - - - - - -

    注意事项

    本文(2022年第一个驱动程序 .pdf)为本站会员(Q****o)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开