Linux内核与驱动学习记录-字符设备驱动程序框架实验
 2021.08.28    |      Linux MMC子系统    |     AilsonJack    |     暂无评论    |     142 views
By: Ailson Jack
Date: 2021-08-28
个人博客: http://www.only2fire.com/
<p style="text-indent: 2em;">根据上一章《<a href="http://www.only2fire.com/archives/137.html" target="_blank">Linux内核与驱动学习记录-字符设备驱动程序框架</a>》的内容,这一章编写了一个例程,作为实验进行说明,加深对字符设备驱动程序开发步骤的理解。<br/></p><p style="text-indent: 2em;">实验代码如下:</p><pre class="brush:cpp;toolbar:false PrismJs">/** &nbsp;*&nbsp;@file&nbsp;chrdev_frame.c &nbsp;*&nbsp;@author&nbsp;Ailson&nbsp;Jack&nbsp;(jackailson@foxmail.com) &nbsp;*&nbsp;@brief &nbsp;*&nbsp;@version&nbsp;1.0 &nbsp;*&nbsp;@date&nbsp;2021-07-31 &nbsp;* &nbsp;*&nbsp;@copyright&nbsp;Copyright&nbsp;(c)&nbsp;2021 &nbsp;* &nbsp;*/ #include&nbsp;&lt;linux/init.h&gt; #include&nbsp;&lt;linux/module.h&gt; #include&nbsp;&lt;linux/kernel.h&gt; #include&nbsp;&lt;linux/cdev.h&gt; #include&nbsp;&lt;linux/fs.h&gt; #define&nbsp;CHRDEV_COUNT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 struct&nbsp;chrdev_mine { &nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;class&nbsp;&nbsp;&nbsp;&nbsp;*class;&nbsp;//&nbsp;指向这个设备应该注册到的&nbsp;struct&nbsp;类的指针 &nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;cdev&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chrdev;&nbsp;//&nbsp;字符设备的定义 &nbsp;&nbsp;&nbsp;&nbsp;dev_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dev;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设备号 }; static&nbsp;struct&nbsp;chrdev_mine&nbsp;chrdev_mine; static&nbsp;const&nbsp;struct&nbsp;file_operations&nbsp;chrdev_mine_fops; /*&nbsp;内核模块加载函数&nbsp;*/ static&nbsp;int&nbsp;__init&nbsp;chrdev_frame_init(void) { &nbsp;&nbsp;&nbsp;&nbsp;printk(KERN_EMERG&nbsp;&quot;[KERN_EMERG]&nbsp;char&nbsp;device&nbsp;Module&nbsp;init!\r\n&quot;); &nbsp;&nbsp;&nbsp;&nbsp;printk(&quot;[default]&nbsp;char&nbsp;device&nbsp;Module&nbsp;init!\r\n&quot;); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设备号的动态申请 &nbsp;&nbsp;&nbsp;&nbsp;alloc_chrdev_region(&amp;chrdev_mine.dev,&nbsp;0,&nbsp;1,&nbsp;&quot;chrdev_frame&quot;); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;字符设备的初始化 &nbsp;&nbsp;&nbsp;&nbsp;cdev_init(&amp;chrdev_mine.chrdev,&nbsp;&amp;chrdev_mine_fops); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;字符设备的注册 &nbsp;&nbsp;&nbsp;&nbsp;cdev_add(&amp;chrdev_mine.chrdev,&nbsp;chrdev_mine.dev,&nbsp;CHRDEV_COUNT); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设备节点的创建 &nbsp;&nbsp;&nbsp;&nbsp;chrdev_mine.class&nbsp;=&nbsp;class_create(THIS_MODULE,&nbsp;&quot;led_chrdev&quot;); &nbsp;&nbsp;&nbsp;&nbsp;device_create(chrdev_mine.class,&nbsp;NULL,&nbsp;chrdev_mine.dev,&nbsp;NULL,&nbsp;&quot;chrdev_frame%d&quot;,&nbsp;0); &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0; } /*&nbsp;内核模块卸载函数&nbsp;*/ static&nbsp;void&nbsp;__exit&nbsp;chrdev_frame_exit(void) { &nbsp;&nbsp;&nbsp;&nbsp;printk(KERN_EMERG&nbsp;&quot;[KERN_EMERG]&nbsp;char&nbsp;device&nbsp;Module&nbsp;exit!\r\n&quot;); &nbsp;&nbsp;&nbsp;&nbsp;printk(&quot;[default]&nbsp;char&nbsp;device&nbsp;Module&nbsp;exit!\r\n&quot;); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设备节点的销毁 &nbsp;&nbsp;&nbsp;&nbsp;device_destroy(chrdev_mine.class,&nbsp;chrdev_mine.dev); &nbsp;&nbsp;&nbsp;&nbsp;class_destroy(chrdev_mine.class); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;字符设备的移除 &nbsp;&nbsp;&nbsp;&nbsp;cdev_del(&amp;chrdev_mine.chrdev); &nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;设备号的归还 &nbsp;&nbsp;&nbsp;&nbsp;unregister_chrdev_region(chrdev_mine.dev,&nbsp;CHRDEV_COUNT); } module_init(chrdev_frame_init); module_exit(chrdev_frame_exit); MODULE_LICENSE(&quot;GPL&nbsp;v2&quot;);&nbsp;//表示模块代码接受的软件许可协议 MODULE_AUTHOR(&quot;Ailson&nbsp;Jack&quot;);&nbsp;//描述模块的作者信息 MODULE_DESCRIPTION(&quot;chrdev&nbsp;frame&quot;);&nbsp;//对模块的简单介绍 MODULE_ALIAS(&quot;chrdev_frame&quot;);&nbsp;//给模块设置一个别名</pre><p style="text-indent: 2em;">Makefile内容如下:<br/></p><pre class="brush:plain;toolbar:false PrismJs">#&nbsp;指向编译出来的&nbsp;linux&nbsp;内核具体路径 KERNEL_DIR&nbsp;=&nbsp;../../kernel/ebf-buster-linux/build_image/build #&nbsp;定义变量,并且导出变量给子&nbsp;Makefile&nbsp;使用 ARCH&nbsp;=&nbsp;arm CROSS_COMPILE&nbsp;=&nbsp;arm-linux-gnueabihf- export&nbsp;ARCH&nbsp;CROSS_COMPILE #&nbsp;obj-m&nbsp;:=&nbsp;&lt;模块名&gt;.o:&nbsp;定义要生成的模块 obj-m&nbsp;:=&nbsp;chrdev_frame.o #&nbsp;选项&nbsp;&quot;-C&quot;:让&nbsp;make&nbsp;工具跳转到&nbsp;linux&nbsp;内核目录下读取顶层&nbsp;Makefile #&nbsp;&quot;M=&quot;&nbsp;表示内核模块源码目录 #&nbsp;$(CURDIR):&nbsp;Makefile&nbsp;默认变量,值为当前目录所在路径 #&nbsp;make&nbsp;modules:&nbsp;执行&nbsp;Linux&nbsp;顶层&nbsp;Makefile&nbsp;的伪目标,它实现内核模块的源码读取并编译为.ko文件 all: &nbsp;&nbsp;&nbsp;&nbsp;$(MAKE)&nbsp;-C&nbsp;$(KERNEL_DIR)&nbsp;M=$(CURDIR)&nbsp;modules .PHONY:clean&nbsp;copy clean: &nbsp;&nbsp;&nbsp;&nbsp;$(MAKE)&nbsp;-C&nbsp;$(KERNEL_DIR)&nbsp;M=$(CURDIR)&nbsp;clean copy: &nbsp;&nbsp;&nbsp;&nbsp;cp&nbsp;*.ko&nbsp;/home/ailsonjack/share/nfs/temp</pre><p style="text-indent: 2em;">将实验代码编译之后的chrdev_frame.ko,下载到板子。<br/></p><p style="text-indent: 2em;">加载内核模块,执行命令:</p><pre class="brush:bash;toolbar:false PrismJs">sudo&nbsp;insmod&nbsp;chrdev_frame.ko</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2021.08.28/003801962921271.png" onclick="preview_image(&#39;/uploads/AilsonJack/2021.08.28/003801962921271.png&#39;)"/></p><p style="text-indent: 2em;">卸载内核模块,执行命令:</p><pre class="brush:bash;toolbar:false PrismJs">sudo&nbsp;rmmod&nbsp;chrdev_frame</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2021.08.28/003801269329837.png" onclick="preview_image(&#39;/uploads/AilsonJack/2021.08.28/003801269329837.png&#39;)"/></p>
欢迎关注博主的公众号呀,精彩内容随时掌握:
热情邀请仔细浏览下博客中的广告,万一有对自己有用或感兴趣的呢。◕ᴗ◕。。
如果这篇文章对你有帮助,记得点赞和关注博主就行了^_^,当然了能够赞赏博主,那就非常感谢啦!
注: 转载请注明出处,谢谢!^_^
暂无评论,要不要来个沙发
发表评论

 
Copyright © 2015~2023  说好一起走   保留所有权利   |  百度统计  蜀ICP备15004292号