Linux内核与驱动学习记录-字符设备驱动程序框架实验
<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">/**
* @file chrdev_frame.c
* @author Ailson Jack (jackailson@foxmail.com)
* @brief
* @version 1.0
* @date 2021-07-31
*
* @copyright Copyright (c) 2021
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#define CHRDEV_COUNT 1
struct chrdev_mine
{
struct class *class; // 指向这个设备应该注册到的 struct 类的指针
struct cdev chrdev; // 字符设备的定义
dev_t dev; // 设备号
};
static struct chrdev_mine chrdev_mine;
static const struct file_operations chrdev_mine_fops;
/* 内核模块加载函数 */
static int __init chrdev_frame_init(void)
{
printk(KERN_EMERG "[KERN_EMERG] char device Module init!\r\n");
printk("[default] char device Module init!\r\n");
// 设备号的动态申请
alloc_chrdev_region(&chrdev_mine.dev, 0, 1, "chrdev_frame");
// 字符设备的初始化
cdev_init(&chrdev_mine.chrdev, &chrdev_mine_fops);
// 字符设备的注册
cdev_add(&chrdev_mine.chrdev, chrdev_mine.dev, CHRDEV_COUNT);
// 设备节点的创建
chrdev_mine.class = class_create(THIS_MODULE, "led_chrdev");
device_create(chrdev_mine.class, NULL, chrdev_mine.dev, NULL, "chrdev_frame%d", 0);
return 0;
}
/* 内核模块卸载函数 */
static void __exit chrdev_frame_exit(void)
{
printk(KERN_EMERG "[KERN_EMERG] char device Module exit!\r\n");
printk("[default] char device Module exit!\r\n");
// 设备节点的销毁
device_destroy(chrdev_mine.class, chrdev_mine.dev);
class_destroy(chrdev_mine.class);
// 字符设备的移除
cdev_del(&chrdev_mine.chrdev);
// 设备号的归还
unregister_chrdev_region(chrdev_mine.dev, CHRDEV_COUNT);
}
module_init(chrdev_frame_init);
module_exit(chrdev_frame_exit);
MODULE_LICENSE("GPL v2"); //表示模块代码接受的软件许可协议
MODULE_AUTHOR("Ailson Jack"); //描述模块的作者信息
MODULE_DESCRIPTION("chrdev frame"); //对模块的简单介绍
MODULE_ALIAS("chrdev_frame"); //给模块设置一个别名</pre><p style="text-indent: 2em;">Makefile内容如下:<br/></p><pre class="brush:plain;toolbar:false PrismJs"># 指向编译出来的 linux 内核具体路径
KERNEL_DIR = ../../kernel/ebf-buster-linux/build_image/build
# 定义变量,并且导出变量给子 Makefile 使用
ARCH = arm
CROSS_COMPILE = arm-linux-gnueabihf-
export ARCH CROSS_COMPILE
# obj-m := <模块名>.o: 定义要生成的模块
obj-m := chrdev_frame.o
# 选项 "-C":让 make 工具跳转到 linux 内核目录下读取顶层 Makefile
# "M=" 表示内核模块源码目录
# $(CURDIR): Makefile 默认变量,值为当前目录所在路径
# make modules: 执行 Linux 顶层 Makefile 的伪目标,它实现内核模块的源码读取并编译为.ko文件
all:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules
.PHONY:clean copy
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
copy:
cp *.ko /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 insmod chrdev_frame.ko</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2021.08.28/003801962921271.png" onclick="preview_image('/uploads/AilsonJack/2021.08.28/003801962921271.png')"/></p><p style="text-indent: 2em;">卸载内核模块,执行命令:</p><pre class="brush:bash;toolbar:false PrismJs">sudo rmmod chrdev_frame</pre><p style="text-align:center"><img src="/uploads/AilsonJack/2021.08.28/003801269329837.png" onclick="preview_image('/uploads/AilsonJack/2021.08.28/003801269329837.png')"/></p>
你可能也喜欢:
暂无评论,要不要来个沙发
发表评论
JLink V9掉固件修复(灯不亮) 3Zephyr笔记2 - 在STM32F429上运行HelloWorld 2计算NandFlash要传入的行地址和列地址 1Linux MMC子系统 - 6.eMMC 5.1工作模式-设备识别模式 0Linux MMC子系统 - 5.eMMC 5.1工作模式-引导模式 0Linux MMC子系统 - 4.eMMC 5.1常用命令说明(2) 0
标签云
Linux嵌入式实用技巧ARM内核学习问题集合CC++编程语言阅读笔记汇编Linux内核完全注释Windows驱动开发计算机基础ARM11ARMv7-ASTM32IDESublimeLinux内核学习eMMCMMC子系统Ubuntu操作系统OfficeVMWareAPUEgccRTOS中断漫游世界随笔感悟开发工具软件应用编程VsCodearmccarmclang编译器ZephyrSPIJLink网卡驱动安装各种芯片库函数NFSμCOS内核sambaFlashUnix命令与脚本输入法Linux内核设计与实现gitRIFFWAVJATGFTPar8161安装centos有线上网μCGUI字库工程建立右键菜单网络文件系统Firefox百度NTFS文件系统CodeBlocksCentOS数据结构算法PhotoShop51KeilQTUltraEditscanfglibc宏定义UIDGID优先级娱乐天地SourceInsight磁盘扇区总线I2CPDFBComparePythonI2SFPUMakefileSWDCPUARP软件推荐FileZilla