上一篇我们介绍了字符设备架构的大概原理、常用的数据结构和函数。接下来,我们撰写一个简单的驱动程序和用户程序,使用户程序可以通过open、release、read、write等常用的文件操作函数,来完成对驱动程序的打开、关闭、读写等控制。

编写代码前,我们再梳理一下思路。想要实现上述效果,我们的工作主要分为三大部分:

  1. 编写驱动程序,并加载到内核中,等待被用户程序调用。在这一步中,如果使用alloc_chrdev_region()动态申请字符设备号,则需要把它打印出来让程序员知道。

  2. 在console控制台下使用mknod命令创建一个设备节点。在这一步中使用的设备号需要与第一部中的保持一致,且设备节点名称需要记录下来,在用户程序中打开设备时需要使用这个名称。

  3. 编写用户程序,通过调用设备节点间接控制驱动程序。打开设备时使用上一步注册字符设备节点时的命名。

一、驱动程序编写

驱动程序完整代码如下,命名为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字符设备驱动实例相关推荐

  1. Linux 驱动开发 三:字符设备驱动框架

    一.参考 (3条消息) Linux 字符设备驱动结构(一)-- cdev 结构体.设备号相关知识解析_知秋一叶-CSDN博客 (3条消息) linux设备驱动框架_不忘初心-CSDN博客_linux设 ...

  2. linux驱动开发5之字符设备驱动新接口

    1.新接口与老接口 1)老接口:register_chrdev static inline int register_chrdev(unsigned int major, const char *na ...

  3. linux 块设备驱动 (三)块设备驱动开发

    linux 块设备驱动 (三)块设备驱动开发 一: 块设备驱动注册与注销 块设备驱动中的第1个工作通常是注册它们自己到内核,完成这个任务的函数是 register_blkdev(),其原型为: int ...

  4. linux 设备驱动(一)——字符设备驱动

    linux 设备驱动(一)--字符设备驱动 一.概述 1.1 设备驱动介绍 1.2. 设备结构 1.2.1 设备号 1.2.2 驱动层次 1.3 设备驱动对外接口 1.4 设备驱动特点 二.字符设备驱 ...

  5. 字符设备驱动基础篇4——字符设备驱动读写接口的操作实践

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html. 一.细节 1.自动分配主设备号 注册函 ...

  6. 字符设备驱动基础篇3——字符设备驱动工作原理

    以下内容源于朱有鹏嵌入式课程的学习,如有侵权,请告知删除. 参考资料:http://www.cnblogs.com/biaohc/p/6575074.html. 1.系统整体工作原理 (1)应用层-& ...

  7. linux驱动开发字符设备,linux驱动开发(三) 字符设备驱动框架

    还是老规矩先上代码 demo.c #include #include#include#include#include int demo_major = 250;int demo_minor = 0;i ...

  8. Linux字符设备驱动程序开发(1)-使用字符设备驱动

    1.编译/安装驱动 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码.因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块.把下面的范例代码拷贝到Linux系统中: memd ...

  9. Linux驱动开发--写一个块设备驱动

    原文地址:[原创] 写一个块设备驱动 http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=2017377&fromuid=288 ...

  10. linux烟雾传感器程序,Linux嵌入式学习-烟雾传感器驱动-字符设备驱动-按键驱动...

    #include #include#include#include#include#include#include#include#include#include#include#include #d ...

最新文章

  1. 冲刺第四天 1.4 FRI
  2. JDK5.0新特性之:泛型
  3. 专访阿里云专有云马劲,一个理性的理想主义者
  4. java 完全匹配,Java 正则表达式匹配模式(贪婪型、勉强型、占有型)
  5. java synchronized静态同步方法与非静态同步方法,同步语句块
  6. 基于JAVA+SpringBoot+Mybatis+MYSQL的校园二手交易平台
  7. 最耗性能的SQL语句
  8. DAG的运用:拓扑排序(AOV),关键路径(AOE)与dp的关系
  9. Python之 if-elif-else
  10. 错误因为数据库正在使用,所以无法获得对数据库的独占访问权的解决方案(转)...
  11. 【MapGIS】常见问题处理
  12. linux系统双显卡切换显卡驱动,Ubuntu 14.04 安装 Nvidia 私有驱动并进行双显卡切换...
  13. 社招简历老被拒?大佬告诉你面试官只中意这些简历,快来看看吧!
  14. 本科计算机专业是机试,华东师大计算机专业复试上机复习攻略+机试技巧
  15. c# + halcon编程(读图、显示图、处理图、鼠标和图像交互)
  16. C语言——一分钟了解数据类型与变量
  17. 图形加速卡技术(大众扫盲篇)
  18. 本地搭建部署gitlab服务并汉化
  19. The CompactFlash Association宣布推出CFexpress(R)2.0规范
  20. 前端 echarts 地图 南海诸岛不显示问题

热门文章

  1. 【JDBC】JDBC入门汇总及范例讲解
  2. VUE学习笔记,最近12,12上班,没得空继续学习vue,先记录一下
  3. 数据分析~中国五大城市PM2.5数据分析01
  4. 信息系统项目管理师考试中涉及到的法律法规知识
  5. jolog扫地机器人怎么样_扫地机器人怎么样?
  6. 阿里巴巴国际站—产品运营工作台操作指南
  7. 计算机应用 一级学科,一级学科、二级学科,考研专业哪个包含了计算机考研方向...
  8. 服务器系统有哪些,各有什么特点?
  9. 彼得林奇的成功投资二——长期经营业绩
  10. Identifying Encrypted Malware Traffic with Contextual Flow Data