字符设备驱动基础1——简单的驱动源代码分析

以下内容源于朱有鹏嵌入式课程的学习,如有侵权请告知删除。

参考博客:linux驱动开发(一) - biaohc - 博客园

一、驱动源代码示例

/********module_test.c代码*********/#include <linux/module.h>	// module_init  module_exit
#include <linux/init.h>		// __init   __exit
#include <linux/fs.h>//这里手动定义主设备号,之前必须确认200没有被使用,查看方法:cat /proc/devices。
//比较好的方法是内核自动分配。
#define MYMAJOR	 200
#define MYNAME		"testchar"static int test_chrdev_open(struct inode *inode, struct file *file)
{// 这个函数中真正应该放置的是打开这个设备的硬件操作代码部分// 但是现在暂时我们写不了这么多,所以用一个printk打印个信息来做代表。printk(KERN_INFO "test_chrdev_open\n");return 0;
}static int test_chrdev_release(struct inode *inode, struct file *file)
{printk(KERN_INFO "test_chrdev_release\n");return 0;
}// 自定义一个file_operations结构体变量,并且去填充.
//这里的.只是结构体变量初始化的一种方法而已。
//file_operations是内核中已经定义好的结构体。
static const struct file_operations test_fops = {.owner		= THIS_MODULE,		// 惯例,直接写即可.open		= test_chrdev_open,	// 将来应用open打开这个设备时// 实际调用的就是这个.open对应的函数.release	= test_chrdev_release,		
};// 模块安装函数
static int __init chrdev_init(void)
{	int ret = -1;printk(KERN_INFO "chrdev_init helloworld init\n");// 在module_init宏调用的函数中去注册字符设备驱动ret = register_chrdev(MYMAJOR, MYNAME, &test_fops);if (ret){printk(KERN_ERR "register_chrdev fail\n");return -EINVAL;}printk(KERN_INFO "register_chrdev success...\n");return 0;
}// 模块卸载函数
static void __exit chrdev_exit(void)
{printk(KERN_INFO "chrdev_exit helloworld exit\n");// 在module_exit宏调用的函数中去注销字符设备驱动unregister_chrdev(MYMAJOR, MYNAME);}module_init(chrdev_init);
module_exit(chrdev_exit);// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL");				// 描述模块的许可证
MODULE_AUTHOR("aston");				// 描述模块的作者
MODULE_DESCRIPTION("module test");	// 描述模块的介绍信息
MODULE_ALIAS("alias xxx");			// 描述模块的别名信息

二、解释说明

1、常用的模块操作命令

lsmod命令(list module,将模块列表显示)

功能是打印出当前内核中已经安装的模块列表。

insmod命令(install module,安装模块)

功能是向当前内核中安装一个模块,用法是insmod xxx.ko

modinfo(module information,模块信息)

功能是打印出一个内核模块的自带信息,用法是modinfo xxx.ko。

rmmod(remove module,卸载模块)

功能是从当前内核中卸载一个已经安装的模块,用法是rmmod xxx(不加.ko后缀)。

2、模块的安装与卸载

(1)模块的安装:insmod与module_init宏

执行insmod命令时,insmod内部实际执行的是使用module_init宏所声明的函数。

比如insmod module_test.ko时,insmod命令内部实际执行的操作是调用chrdev_init函数

(2)模块的卸载:rmmod和module_exit宏

和上面阐述的是同一个道理,可以使用lsmod命令查看rmmod前后系统的模块记录变化。

3、模块的版本信息

(1)使用modinfo命令查看模块的版本信息

root@ubuntu:/home/xjh/iot/embedded_basic/rootfs/tmp# modinfo module_test.ko 
filename:       /home/xjh/iot/embedded_basic/rootfs/tmp/module_test.ko
alias:          alias xxx
description:    module test
author:         aston
license:        GPL
depends:  //这是依赖,比如usb-wifi的驱动依赖usb的驱动      
vermagic:       2.6.35.7 preempt mod_unload ARMv7  //这是版本号
root@ubuntu:/home/xjh/iot/embedded_basic/rootfs/tmp#

(2)驱动的版本信息与内核的版本信息要一致

使用insmod命令安装驱动模块时,驱动模块的版本信息要与内核版本信息一致。这是一种安全措施,目的是为了保证模块和内核的兼容性。如果不一致,将报错:

insmod: ERROR: could not insert module module_test.ko: Invalid module format;

如何保持一致?确保某个内核源码树,既用来生成用来烧录的内核镜像,也用来编译驱动模块。

4、模块中常用宏

MODULE_xxx,这些宏用来添加驱动模块描述信息。

(1)MODULE_LICENSE,模块的许可证。

一般声明为GPL许可证,缺少可能会出现莫名其妙的错误(一些明显存在的函数提升找不到)。

(2)MODULE_AUTHOR,编写作者。

(3)MODULE_DESCRIPTION,模块描述。

(4)MODULE_ALIAS,别名信息。

5、函数修饰符__init、__exit

(1)函数修饰符__init

1)本质

__init 本质上是宏定义,在内核源代码中有#define __init xxxx。

作用

它的作用,是将所修饰的函数放入.init.text段(默认情况下函数被放入.text段中)。

使用这个修饰符有什么好处呢?

被__init 所修饰的函数,都被链接器链接放入.init.text段中。内核启动时会统一加载.init.text段中的这些模块安装函数,加载完后就会把这个段给释放掉以节省内存(因为安装完后这些函数就没用了)。

补充说明

下划线越多,越深入内核深处。

(2)函数修饰符__exit

和__init类似的意义,不赘述。

6、printk函数详解

(1)printk函数作用

在内核源码中用来打印信息的函数。

(2)printk和printf的差别

printf是C库函数,在应用层编程中使用,不能在linux内核源代码中使用;

printk是内核源码中的一个普通函数,只能在内核源码范围内使用,不能在应用编程中使用。

(3)printk可以设置打印级别

1)打印级别的意义

应用程序中的调试信息要么全部打开要么全部关闭,一般用条件编译(DEBUG宏)来实现;但是内核非常庞大,打印信息非常多,因此需要设置打印级别。printk的打印级别,可以用来控制printk打印的这条信息是否在终端上显示的。

2)打印级别

3)查看打印级别

可以使用“cat /proc/sys/kernel/printk”查看打印级别。

4)设置打印级别

可以用“echo 4 /proc/sys/kernel/printk”设置打印级别为4。 

5)命令行设置打印信息级别

在命令行中也可以设置打印信息级别,级别值为0-7。在执行printk的时候,对比printk中的打印级别与命令行中设置的打印级别,发现printk小于命令行设置级别的信息会被放行打印出来,大于的就被拦截。但ubuntu中不管如何设置级别,都不能直接打印出来,必须使用dmesg命令去查看。

7、关于驱动模块中的头文件

驱动源代码中包含的头文件,和应用程序中包含的头文件不同。

应用程序所包含的头文件,是应用层的头文件,一般是编译器带来的,与操作系统无关。比如 gcc 的头文件路径在 /usr/include下。

驱动源码所包含的头文件,是内核源代码include目录下的头文件,属于内核源码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461299.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

字符设备驱动基础3——使用register_chrdev()函数注册字符设备

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、系统工作原理 1、工作流程 系统的整体工作流程是&#xff1a;应用层—>API—>设备驱动—>硬件。 操作系统提供的API包括open、read、write、close等函数&#xff0c;它们只是一种操作逻…

win7在未关闭vmware情况下直接关机,导致虚拟机无法克隆

今天有点小激动啊&#xff0c;着急关机&#xff0c;结果发现重启之后的虚拟机不能进行克隆操作。系统提示如下&#xff1a;the Specific Virtual Disk Needs Repair .查询“度娘”&#xff0c;突然看到一篇文章说&#xff0c;删除这啊&#xff0c;修改那的....特别复杂&#xf…

hdu 1159(最长公共子序列)

题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1159 思路&#xff1a;dp[i][j]表示s1从0~i-1,s2从0~j-1的最长公共子序列&#xff1b; 递推方程为&#xff1a;dp[i][j](s1[i-1]s2[j-1])?d[i-1][j-1]1:max(dp[i-1][j],dp[i][j-1]); View Code 1 #include<…

mysql applier_MySQL推出Applier,可实时复制数据到Hadoop-阿里云开发者社区

http://labs.mysql.comMySQL复制操作可以将数据从一个MySQL服务器(主)复制到其他的一个或多个MySQL服务器(从)。试想一下&#xff0c;如果从服务器不再局限为一个MySQL服务器&#xff0c;而是其他任何数据库服务器或平台&#xff0c;并且复制事件要求实时进行&#xff0c;是否可…

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

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、细节提要 1、与用户与内核数据交换有关的函数 &#xff08;1&#xff09;copy_from_user()函数 该将数据从用户空间复制到内核空间。 如果成功复制则返回0&#xff0c;如果不成功复制则返回尚未…

mysql分区表mycat_MySQL 中间件之Mycat垂直分表配置

垂直分表就是将一个库下的多个表拆分到多个MySQL实例&#xff0c;实现库压力分流。通过GTID模式复制&#xff0c;db01与db02之间不进行任何连接与复制当前环境&#xff1a;mycat --> db01与db02db01 --> db03db02 --> db04当前垂直分表架构&#xff1a;后端数据库创建…

深入浅出mysql gtid_深入理解MySQL GTID

GTID的概念何为GITDGTID(global transaction identifier)是全局事务标识符&#xff0c;在MySQL5.6版本中作为一个超级特性被推出。事务标识不仅对于Master(起源)的服务器来说是惟一的&#xff0c;而且在整个复制拓扑架构来说&#xff0c;也是全局唯一的。1.GTID的格式GTID sou…

winform 64位系统中使用

WINFOR编译成X86的 转载于:https://blog.51cto.com/agilitygod/1419939

long 转为string_面试必问 Redis数据结构底层原理String、List篇

点击关注上方“Java大厂面试官”&#xff0c;第一时间送达技术干货。阅读文本大概需要 8 分钟。前言今天来整理学习下Redis有哪些常用数据结构&#xff0c;都是怎么使用的呢&#xff1f;首先看下全局存储结构。全局存储结构基础你们肯定都知道&#xff0c;redis支持的基础数据结…

wpf 3D学习

最近在看一些关于wpf 3d的效果&#xff0c;研究了一些代码特效&#xff0c;现在和广大博友共享一下. 首先用到的是MeshGeometry3D&#xff0c;msdn上介绍&#xff1a;用于生成三维形状的三角形基元。主要有4个依赖属性&#xff1a;NormalsProperty&#xff0c;PositionsPropert…

unicode字符、python乱码问题

http://www.cnblogs.com/BeginMan/archive/2013/08/08/3246619.html#a1 Python常见常用知识点http://blog.csdn.net/tingsking18/article/details/4033645 Unicode和Python的中文处理如何让Python的Unicode字符串支持中文&#xff1f;要想利用Python的Unicode机制处理字符串&…

win10下如何安装vb6.0sp6_Mac如何安装win10系统?Parallels Desktop 15 Mac安装win10系统教程...

Parallels Desktop 15 mac版是mac上非常强大也非常好用的虚拟机软件&#xff0c;最新版本的parallels desktop mac 15针对最新的Windows 10更新和macOS Catalina&#xff08;10.15&#xff09;进行了优化。今天分享的内容就是Parallels Desktop 15 mac版如何安装win10系统。PD虚…

字符设备驱动高级篇5——静态映射表的建立过程,动态映射结构体方式操作寄存器

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 补充内容&#xff1a;字符设备驱动基础5——驱动如何操控硬件_天糊土的博客-CSDN博客 一、静态映射表的建立过程 关于“静态映射表的建立”这部分内容&#xff0c;有以下三个关键&#xff1a; &…

python 分布图_python数据分布型图表柱形分布图系列带误差线的柱形图

柱形分布图系列柱形分布图系列使用柱形图的方式展示数据的分布规律&#xff1b;可以借助误差线或散点图&#xff1b;带误差线的柱形图就是使用每个类别的均值作为柱形的高度&#xff1b;再根据每个类别的标准差绘制误差线&#xff1b;缺点&#xff1a;无法显示数据的分布情况&a…

[汇编] 002基础知识-CPU和寄存器

CPU是什么 当然这里的内存不仅仅指电脑上的内存&#xff0c;例如&#xff1a;我的金士顿8G内存&#xff0c;七彩虹1G独显&#xff0c;在这里来说&#xff0c;显卡也是有内存的(寄存器) CPU如何控制其它部件的&#xff1f; 问题&#xff1a;CPU是如何和电脑主机中其它芯片有条不…

字符设备驱动高级篇6——内核提供的读写寄存器接口

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 1、访问寄存器的方式 之前对寄存器的操作&#xff0c;都是先定义指向寄存器的指针&#xff0c;然后再解引用来对寄存器进行操作。这是因为ARM体系中&#xff0c;内存和IO是统一编址的。但是其他体系…

java台球游戏设计原理_Java实现简单台球游戏

Java实现简单台球桌问题&#xff0c;供大家参考&#xff0c;具体内容如下需求&#xff1a;使小球可以在桌面上移动&#xff0c;移动到桌面边缘将被弹回&#xff0c;显示小区的移动素材&#xff1a;小球照片桌球照片程序源代码&#xff1a;package 桌球游戏;import java.awt.*;i…

关于java assertion

大部分转载自参考资料&#xff1a;http://www.ibm.com/developerworks/cn/java/l-javaassertion/index.html assertion(断言)在软件开发中是一种常用的调试方式&#xff0c;assertion就是在程序中的一条语句&#xff0c;它对一个boolean表达式进行检查&#xff0c;一个正确程序…

IOC是什么?

2019独角兽企业重金招聘Python工程师标准>>> Inversion of Control&#xff0c;即反转控制&#xff0c;或许说为依赖注入更为合适。IoC就是一种设计模式。 Interface Driven Design接口驱动&#xff0c;接口驱动有很多好处&#xff0c;可以提供不同灵活的子类实现&a…

poj2516Minimum Cost

http://poj.org/problem?id2516 建图的时候 有个地方写错了 卡了半年。。 题意看了N久啊 有N个店主需要K种物品 有M个供应点 每个供应点有K种物品 其实是算K次最小费用 然后叠加 分解开来这题就是求把某种物品从供应点送到店主那里 多个源点-》多个汇点 所以加一个超级源点 和…