linux驱动开发(三):Linux字符设备驱动实例
上一篇我们介绍了字符设备架构的大概原理、常用的数据结构和函数。接下来,我们撰写一个简单的驱动程序和用户程序,使用户程序可以通过open、release、read、write等常用的文件操作函数,来完成对驱动程序的打开、关闭、读写等控制。
编写代码前,我们再梳理一下思路。想要实现上述效果,我们的工作主要分为三大部分:
编写驱动程序,并加载到内核中,等待被用户程序调用。在这一步中,如果使用alloc_chrdev_region()动态申请字符设备号,则需要把它打印出来让程序员知道。
在console控制台下使用mknod命令创建一个设备节点。在这一步中使用的设备号需要与第一部中的保持一致,且设备节点名称需要记录下来,在用户程序中打开设备时需要使用这个名称。
编写用户程序,通过调用设备节点间接控制驱动程序。打开设备时使用上一步注册字符设备节点时的命名。
一、驱动程序编写
驱动程序完整代码如下,命名为cdev_driver.c。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>MODULE_LICENSE("GPL");
MODULE_AUTHOR("zz");static dev_t devno;#define KMAX_LEN 32static int demo_open(struct inode *ind, struct file *fp)
{printk("demo open\n");return 0;
}static int demo_release(struct inode *ind, struct file *fp)
{printk("demo release\n");return 0;
}static ssize_t demo_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
{int rc;char kbuf[KMAX_LEN] = "read test\n"; if (size > KMAX_LEN)size = KMAX_LEN;rc = copy_to_user(buf, kbuf, size);if(rc < 0) {return -EFAULT;pr_err("copy_to_user failed!");}return size;
}static ssize_t demo_write(struct file *fp, const char __user *buf, size_t size, loff_t *pos)
{int rc;char kbuf[KMAX_LEN];if (size > KMAX_LEN)size = KMAX_LEN;rc = copy_from_user(kbuf, buf, size);if(rc < 0) {return -EFAULT;pr_err("copy_from_user failed!");}printk("%s", kbuf);return size;
}static struct file_operations fops = {.open = demo_open,.release = demo_release,.read = demo_read,.write = demo_write,
};static struct cdev cd;static int demo_init(void)
{int rc;rc = alloc_chrdev_region(&devno, 0, 1, "test");if(rc < 0) {pr_err("alloc_chrdev_region failed!");return rc;}printk("MAJOR is %d\n", MAJOR(devno));printk("MINOR is %d\n", MINOR(devno));cdev_init(&cd, &fops);rc = cdev_add(&cd, devno, 1);if (rc < 0) {pr_err("cdev_add failed!");return rc;}return 0;
}static void demo_exit(void)
{cdev_del(&cd);unregister_chrdev_region(devno, 1);return;
}module_init(demo_init);
module_exit(demo_exit);
二、应用程序编写
驱动程序完全编写完毕,下面编写应用程序。在应用程序中,我们要完成下面的操作:使用open函数打开字符设备,使用read函数从字符设备中读出字符串“read test”,使用write函数向字符设备中写入字符串“write test”,使用close释放字符设备。我们将设备节点的名称命名为test_chr_dev。代码如下,代码文件命名为app.c。
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>int main()
{int rc;char buf[32];int fd = open("/dev/test_chr_dev", O_RDWR);if (fd < 0) {printf("open file failed!\n");return -1;}read(fd, buf, 32);printf("%s", buf);write(fd, "write test\n", 32);close(fd);return 0;
}
三、编写Makefile。
ifneq ($(KERNELRELEASE),)obj-m := cdev_driver.o
elseKDIR := /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)
all:make -C $(KDIR) M=$(PWD) modules
clean:make -C $(KDIR) M=$(PWD) clean
endif
五、程序运行
首先make编译驱动代码。
然后gcc编译用户程序代码。
sudo -s指令进入root模式,insmod加载模块。
dmesg查看一下系统为设备分配的设备号时多少,可以看出主设备号时240。
然后首先使用mknod指令向系统中创建设备节点,注意字符设备号也要设置成240,节点名称要与用户程序中打开的设备文件的名称保持一致,即test_chr_dev。
注:如果删除字符设备,只需要使用rm指令删除字符设备节点即可。
rm /dev/test_chr_dev
运行应用程序。可以看到读功能正常。
dmesg打印一下内核信息,可以看到设备打开、写功能、释放正常。
linux驱动开发(三):Linux字符设备驱动实例相关推荐
- Linux 驱动开发 三:字符设备驱动框架
一.参考 (3条消息) Linux 字符设备驱动结构(一)-- cdev 结构体.设备号相关知识解析_知秋一叶-CSDN博客 (3条消息) linux设备驱动框架_不忘初心-CSDN博客_linux设 ...
- linux驱动开发5之字符设备驱动新接口
1.新接口与老接口 1)老接口:register_chrdev static inline int register_chrdev(unsigned int major, const char *na ...
- linux 块设备驱动 (三)块设备驱动开发
linux 块设备驱动 (三)块设备驱动开发 一: 块设备驱动注册与注销 块设备驱动中的第1个工作通常是注册它们自己到内核,完成这个任务的函数是 register_blkdev(),其原型为: int ...
- linux 设备驱动(一)——字符设备驱动
linux 设备驱动(一)--字符设备驱动 一.概述 1.1 设备驱动介绍 1.2. 设备结构 1.2.1 设备号 1.2.2 驱动层次 1.3 设备驱动对外接口 1.4 设备驱动特点 二.字符设备驱 ...
- 字符设备驱动基础篇4——字符设备驱动读写接口的操作实践
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html. 一.细节 1.自动分配主设备号 注册函 ...
- 字符设备驱动基础篇3——字符设备驱动工作原理
以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html. 1.系统整体工作原理 (1)应用层-& ...
- linux驱动开发字符设备,linux驱动开发(三) 字符设备驱动框架
还是老规矩先上代码 demo.c #include #include#include#include#include int demo_major = 250;int demo_minor = 0;i ...
- Linux字符设备驱动程序开发(1)-使用字符设备驱动
1.编译/安装驱动 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码.因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块.把下面的范例代码拷贝到Linux系统中: memd ...
- Linux驱动开发--写一个块设备驱动
原文地址:[原创] 写一个块设备驱动 http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=2017377&fromuid=288 ...
- linux烟雾传感器程序,Linux嵌入式学习-烟雾传感器驱动-字符设备驱动-按键驱动...
#include #include#include#include#include#include#include#include#include#include#include#include #d ...
最新文章
- 冲刺第四天 1.4 FRI
- JDK5.0新特性之:泛型
- 专访阿里云专有云马劲,一个理性的理想主义者
- java 完全匹配,Java 正则表达式匹配模式(贪婪型、勉强型、占有型)
- java synchronized静态同步方法与非静态同步方法,同步语句块
- 基于JAVA+SpringBoot+Mybatis+MYSQL的校园二手交易平台
- 最耗性能的SQL语句
- DAG的运用:拓扑排序(AOV),关键路径(AOE)与dp的关系
- Python之 if-elif-else
- 错误因为数据库正在使用,所以无法获得对数据库的独占访问权的解决方案(转)...
- 【MapGIS】常见问题处理
- linux系统双显卡切换显卡驱动,Ubuntu 14.04 安装 Nvidia 私有驱动并进行双显卡切换...
- 社招简历老被拒?大佬告诉你面试官只中意这些简历,快来看看吧!
- 本科计算机专业是机试,华东师大计算机专业复试上机复习攻略+机试技巧
- c# + halcon编程(读图、显示图、处理图、鼠标和图像交互)
- C语言——一分钟了解数据类型与变量
- 图形加速卡技术(大众扫盲篇)
- 本地搭建部署gitlab服务并汉化
- The CompactFlash Association宣布推出CFexpress(R)2.0规范
- 前端 echarts 地图 南海诸岛不显示问题
热门文章
- 【JDBC】JDBC入门汇总及范例讲解
- VUE学习笔记,最近12,12上班,没得空继续学习vue,先记录一下
- 数据分析~中国五大城市PM2.5数据分析01
- 信息系统项目管理师考试中涉及到的法律法规知识
- jolog扫地机器人怎么样_扫地机器人怎么样?
- 阿里巴巴国际站—产品运营工作台操作指南
- 计算机应用 一级学科,一级学科、二级学科,考研专业哪个包含了计算机考研方向...
- 服务器系统有哪些,各有什么特点?
- 彼得林奇的成功投资二——长期经营业绩
- Identifying Encrypted Malware Traffic with Contextual Flow Data