globalmem

linux 设备驱动开发详解时,字符设备驱动一章,写的测试代码和应用程序,加上自己的操作,对初学者我觉得非常有帮助。

写这篇文章的原因是因为我看了我之前发表的文章,还没有写过字符设备相关的,至于里面提到的结构体的作用,有很多详细的文章说明,我就不做更深的叙述。

代码在github上,点击下面阅读原文可以直达

https://github.com/weiqifa0/globalmem/blob/main/README.md

把这部分放在github上也有好处,后续可以增加删除一些东西,以后自己需要使用的时候也方便许多。

我们讨论字符设备驱动,就有必要知道他的结构体和头文件,像一些后来的封装什么的,大部分还是脱离不了操作这个结构体里面的东西。

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CDEV_H
#define _LINUX_CDEV_H#include <linux/kobject.h>
#include <linux/kdev_t.h>
#include <linux/list.h>
#include <linux/device.h>struct file_operations;
struct inode;
struct module;struct cdev {struct kobject kobj; /*内嵌kobject结构体,方便以后应用,也会在sys下生成相关设备文件*/struct module *owner;/*所属于的模块,正常就是本模块THIS_MODULE*/const struct file_operations *ops;/*文件的操作结构体,设备也是一个文件*/struct list_head list;/*字符设备的链表头*/dev_t dev;/*设备号*/unsigned int count;
} __randomize_layout;
/*初始化cdev,并建立和file_operation的联系*/
void cdev_init(struct cdev *, const struct file_operations *);
/*申请cdev内存*/
struct cdev *cdev_alloc(void);void cdev_put(struct cdev *p);int cdev_add(struct cdev *, dev_t, unsigned);void cdev_set_parent(struct cdev *p, struct kobject *kobj);
int cdev_device_add(struct cdev *cdev, struct device *dev);
void cdev_device_del(struct cdev *cdev, struct device *dev);void cdev_del(struct cdev *);void cd_forget(struct inode *);#endif

加载内核模块insmod globalmem.ko 错误需要的修改。

insmod: can't insert 'globalmem.ko': Device or resource busy

出错的原因:

模块使用的是静态分配设备号的方式,而这个设备号已经被系统中的其他设备所占用。查看未被占用的设备号,需要到pro/devices下面去查看。

查看设备号的方法:

# cat /proc/devices

编译内核版本

#uname -a
Linux bsp-ubuntu1804 4.15.0-117-generic #118-Ubuntu SMP Fri Sep 4 20:02:41 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

加载模块之后使用lsmod查看模块

weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo insmod globalmem.koweiqifa@bsp-ubuntu1804:~/c/globalmem$ lsmod |grep global
globalmem              16384  0
weiqifa@bsp-ubuntu1804:~/c/globalmem$weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /proc/devices |grep global
230 globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$

创建设备文件节点

使用mknod创建设备节点的时候,后面跟上的参数需要跟我们在/proc/devices下面看到的对应,也就是我们在驱动里面申请的主设备号。

weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo mknod /dev/globalmem c 230 0
weiqifa@bsp-ubuntu1804:~/c/globalmem$ ls /dev/globalmem -al
crw-r--r-- 1 root root 230, 0 Dec 22 16:19 /dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$

使用命令读写设备文件

Linux 下的 echo 和cat 命令是十分有用,这两个命令可以让在不写代码的情况下就可以完成调试读写设备。

weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo chmod 777 /dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo echo "linux" > /dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /dev/globalmem
linux
cat: /dev/globalmem: No such device or address
weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /dev/globalmem
linux
cat: /dev/globalmem: No such device or address
weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo echo "linuxgdb" > /dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /dev/globalmem
linuxgdb
cat: /dev/globalmem: No such device or address
weiqifa@bsp-ubuntu1804:~/c/globalmem$

通过代码来读写设备文件

代码在下面阅读原文的链接里面。

weiqifa@bsp-ubuntu1804:~/c/globalmem$ gcc app-main.c && ./a.out
str:LINUX,GDB
weiqifa@bsp-ubuntu1804:~/c/globalmem$

使用传入参数设置主设备号

内核模块参数我觉得是一个比较冷门的知识点,冷门的原因是因为我们在做项目的时候很少使用这个参数,但是实际上这个参数非常有用。

我们可以把内核模块当做main函数,main函数是可以接收传参的,内核模块也可以在加载的时候接收传入的参数。

如下是把主设备号传给内核模块,但是需要注意,这个主设备号不能被占用了。


weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo insmod globalmem.ko globalmem_major=231
weiqifa@bsp-ubuntu1804:~/c/globalmem$ cat /proc/devices |grep globalmem
231 globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$

增加自动创建设备节点的驱动文件

每次手动创建设备文件节点总是很麻烦,而且在实际编写设备驱动的时候,不会出现自己手动创建设备节点这种低端的操作。

当然了,聪明的内核提供了接口让我们在注册驱动的时候也把设备文件节点注册上去。

具体代码可以查看globalmem2.c里面的代码。

weiqifa@bsp-ubuntu1804:~/c/globalmem$ chmod 777 globalmem.ko
weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo insmod globalmem.ko
[sudo] password for weiqifa:
weiqifa@bsp-ubuntu1804:~/c/globalmem$ ls /dev/globalmem
/dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$ ls /dev/globalmem -al
crw------- 1 root root 238, 0 Dec 22 17:18 /dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$/*修改权限后才可以正常进行独写操作*/
weiqifa@bsp-ubuntu1804:~/c/globalmem$ sudo chmod 777 /dev/globalmem
weiqifa@bsp-ubuntu1804:~/c/globalmem$ gcc app-main.c && ./a.out
write data ok!
str:LINUX,GDB
weiqifa@bsp-ubuntu1804:~/c/globalmem$

使用lseek操作文件位置

具体对应的文件是app-main2.c

weiqifa@bsp-ubuntu1804:~/c/globalmem$ gcc app-main2.c && ./a.out
file ret:0
write data ok! fd:3
str:123456789ABCDEF10111213141516171819201617181920
lseek:1
str:23456789ABCDEF10111213141516171819201617181920
weiqifa@bsp-ubuntu1804:~/c/globalmem$

推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

Linux字符设备驱动实例相关推荐

  1. Linux字符设备驱动中container_of宏的作用

    Linux字符设备驱动中container_of宏的作用 首先看看这个宏的原型: container_of(ptr,type,member) 功能:根据一个结构体变量中的一个成员变量的指针来获取指向整 ...

  2. Linux 字符设备驱动结构(一)—— cdev 结构体、设备号相关知识解析

    一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数 ...

  3. ()shi linux字符设备,Linux字符设备驱动基础(三)

    Linux字符设备驱动基础(三) 6 创建设备节点 6.1 手动创建设备节点 查看申请的设备名及主设备号: cat /proc/devices # cat /proc/devices Characte ...

  4. linux设备模型 字符设备,Linux 字符设备驱动模型之框架解说

    一.软件操作硬件设备模型 在进行嵌入式开发的过程中,在常做的事情就是驱动配置硬件设 备,然后根据功能需求使用硬件设备,实现功能的逻辑.如下图为其 相互之间的关系. 如上图所示: 驱动程序:主要作为操作 ...

  5. linux字符设备文件的打开操作,Linux字符设备驱动模型之字符设备初始化

    因为Linux字符设备驱动主要依赖于struct cdev结构,原型为: 所以我们需要对所使用到的结构成员进行配置,驱动开发所使用到的结构成员分别为:[unsigned int count;].[de ...

  6. linux生成驱动编译的头文件,嵌入式Linux字符设备驱动——5生成字符设备节点

    嵌入式Linux字符设备驱动开发流程--以LED为例 前言 留空 头文件 #include 查看系统设备类 ls /sys/class 设备类结构体 文件(路径):include/linux/devi ...

  7. linux字符设备驱动的 ioctl 幻数

    在Linux字符设备驱动入门(一)中,我们实现了字符设备的简单读写字符功能,接下来我们要在这个基础上加入ioctl功能.首先,我们先来看看3.0内核下../include/linux/fs.h中fil ...

  8. Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析

    前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...

  9. linux字符设备驱动在哪里设置,从点一个灯开始学写Linux字符设备驱动!

    原标题:从点一个灯开始学写Linux字符设备驱动! [导读] 前一篇文章,介绍了如何将一个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成一 ...

最新文章

  1. 泊松回归(Poisson regression)、COX回归、分类器变回归器、回归算法注意事项、多重共线性问题
  2. (DFS)求出n个数中选择m个数的所有可能
  3. android开机启动service
  4. openFoam源码中的C++
  5. python求定积分的函数_手搓计算化学(GTO积分by python)
  6. java 集合工具类_Java 集合 Collections工具类
  7. Oracle11g补丁安装(单实例)
  8. 科普:一片晶圆可以切多少个芯片?
  9. 看到别人比自己优秀,为何会难受?
  10. 语音编码标准(G.711 G.723 G.726 G.729 iLBC) .
  11. Android中多个style,Android设计规范 Material Design-Style(4图像)
  12. selenium新浪邮箱注册句柄切换实战
  13. 做测试8年,33岁前只想追求大厂高薪,今年只求稳定收入
  14. 从宜人贷系统架构看互联网高并发对金融系统架构的挑战
  15. Python基础系列N讲 | 1500字详解Anaconda安装教程(附安装包)
  16. 丰田生产方式精髓-杜绝浪费
  17. STC89C51——中断系统
  18. 2019聊大考研计算机调剂,聊城大学2019考研调剂信息
  19. GDI 输出文字、画点、线、三角形、矩形、圆、椭圆、多边形
  20. 软件测试项目经验案例_自学软件测试如何得到项目经验

热门文章

  1. node.js Websocket消息推送---GoEasy
  2. ubuntu下安装拼音输入法ibus
  3. 利用ACS来实现AAA服务
  4. 在线检测PR值,外链,批量
  5. 计算t-test 的C程序
  6. 加密和解密算法的兩個實現
  7. thinkphp如何增加session的过期时间
  8. 企业网站 源码 服务邮箱:_公司企业邮箱购买,外贸企业邮箱用哪家服务好?
  9. 深度学习之目标检测:R-CNN、Fast R-CNN、Faster R-CNN
  10. oracle 未找到段的存储定义,Exp-00003 no storage definition found issue in oracle 11g (未找到段 (0,0) 的存储定义)...