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

参考资料:http://www.cnblogs.com/biaohc/p/6575074.html

module_test.c代码

#include <linux/module.h>      // module_init  module_exit
#include <linux/init.h>           // __init   __exit
#include <linux/fs.h>#define MYMAJOR      200//这里手动地定义主设备号,之前必须确认200没有被用,查看方法是cat /proc/devices。比较好的方法是内核自动分配。
#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打开这个设备时实际调用的.release = test_chrdev_release,     // 就是这个.open对应的函数
};// 模块安装函数
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、模块的安装

insmod与module_init宏

  • insmod与module_init宏有关联,即执行insmod命令时,insmod内部实际执行的是使用module_init宏所声明的函数。
  • 比如insmod module_test.ko时,insmod命令内部实际执行的操作是调用chrdev_init函数。
  • 由上表明,模块的安装函数得自己编写,内核自身没有此模块的安装函数,内核只是帮忙调用你所编写的模块安装函数。
  • 除了调用绑定的函数外,在内部还执行了另外一些事情。

3、模块卸载

rmmod和module_exit宏

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

4、模块的版本信息

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

(2)内核zImage中也有一个确定的版本信息;

(3)insmod时,驱动的版本信息和内核的版本信息要一致

  • 否则不能安装,报错信息为:insmod: ERROR: could not insert module module_test.ko: Invalid module format;
  • 模块的版本信息是为了保证模块和内核的兼容性,是一种安全措施;

(4)如何保证模块的vermagic和内核的vermagic一致?

  • 确保某个内核源码树,即用来生成用于烧录的zImage,也用来编译驱动模块。

5、模块中常用宏

MODULE_xxx这种宏作用是用来添加模块描述信息,见代码的解释。

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

  • 一般声明为GPL许可证,而且最好不要少,否则可能会出现莫名其妙的错误(譬如一些明显存在的函数提升找不到)。

(2)MODULE_AUTHOR 编写作者

(3)MODULE_DESCRIPTION 模块描述

(4)MODULE_ALIAS 别名信息

6、函数修饰符

(1)__init

  • 本质上是宏定义,在内核源代码中有#define __init xxxx
  • 作用:将所修饰的函数放入.init.text段(默认情况下函数是被放入.text段中)。
  • 这类函数都被链接器链接放入.init.text段中,因此这类函数被统一放在一起。
  • 内核启动时,会统一加载.init.text段中的这些模块安装函数,加载完后就会把这个段给释放掉以节省内存。因此安装完后这些函数就没用了。
  • 下划线越多,越深入内核深处。

(2)__exit

7、static

8、printk函数详解

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

(2)printk和printf的差别

  • printf是C库函数,在应用层编程中使用,不能在linux内核源代码中使用;
  • printk是内核源码中的一个普通函数,只能在内核源码范围内使用,不能在应用编程中使用。

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

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

(4)操作系统的命令行中也有一个打印信息级别属性,值为0-7。

  • 执行printk的时候,对比printk中的打印级别与命令行中设置的打印级别;
  • 小于命令行设置级别的信息会被放行打印出来,大于的就被拦截的。
  • 但ubuntu中不管如何设置级别,都不能直接打印出来,必须使用dmesg命令去查看。

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

  • 驱动源代码中包含的头文件,和应用编程程序中包含的头文件不同。
  • 应用编程中,所包含的头文件是应用层的头文件,是应用程序的编译器带来的(譬如gcc的头文件路径在 /usr/include下,与操作系统无关)。
  • 驱动源码属于内核源码的一部分,驱动源码中的头文件,即内核源代码目录下的include目录下的头文件。
  • 内核顶层目录下的include目录下的linux目录下,有init.h。

10、Makefile分析

#ubuntu的内核源码树,如果要编译在ubuntu中安装的模块就打开这2个
#KERN_VER = $(shell uname -r)
#KERN_DIR = /lib/modules/$(KERN_VER)/build //这是ubuntu提供的在本Ubuntu环境下开发驱动的内核源码树,因此如果想在此Ubuntu中开发驱动,则内核源码树目录就是它# 开发板的linux内核的源码树目录
KERN_DIR = /root/driver/kernelobj-m    += module_test.oall:make -C $(KERN_DIR) M=`pwd` modules cp:cp *.ko /root/porting_x210/rootfs/rootfs/driver_test.PHONY: clean
clean:make -C $(KERN_DIR) M=`pwd` modules clean

(1)KERN_DIR,表示用来编译这个模块的内核源码树的目录;

(2)obj-m += module_test.o,-m表示将module_test.c文件编译成一个单独的模块;

(3)make -C $(KERN_DIR) M=`pwd` modules,此命令用来编译模块。

  • 利用make -C $(KERN_DIR)进入指定的内核源码树目录,然后在源码目录树下,借用内核源码中定义的模块编译规则,去编译该模块modules;
  • 其实就是make modules,modules是内核中的一个目标;中间的是参数,表明到某个目录下进行编译,编译完后回到当前目录(反引号表示它是一个命令)。

(4)编译完成后,把生成的文件拷贝到当前目录下,完成编译。

(5)make clean ,用来清除编译痕迹。

(5)总结

  • 模块的makefile非常简单,本身并不能完成模块的编译,而是通过make -C进入到内核源码树下,借用内核源码的体系来完成模块的编译链接。
  • 此Makefile非常模式化,(3)和(4)(5)是永远不用动的,只有(1)和(2)需要动。

字符设备驱动基础篇1——简单的驱动源码分析相关推荐

  1. AI作曲基础-Python编程作曲软件篇-FoxDot文档及源码分析-官方教程01

    AI作曲基础-Python编程作曲软件篇-FoxDot文档及源码分析-官方教程01 前言 本系列系列目录放在文尾: 本系列是AI作曲的基础,暂时和AI关系不大,但尤为重要: 借助FoxDot,从文档分 ...

  2. 《微信小程序-进阶篇》Lin-ui组件库源码分析-列表组件List(一)

    大家好,这是小程序系列的第二十篇文章,在这一个阶段,我们的目标是 由简单入手,逐渐的可以较为深入的了解组件化开发,从本文开始,将记录分享lin-ui的源码分析,期望通过对lin-ui源码的学习能加深组 ...

  3. java刷卡计时计次源码美萍_Java 定时调配 Timer 类和定任务 TimerTask 类(一篇详细且完整的源码分析以及四种简单的使用方法)...

    前言 在我们日常生活中,我们常常会遇到有关计时器的事情.如商城类项目会在某年某月某日某时某分某秒进行特价活动,那么当时间到达这个时间点上的时候该事件就会触发. 1.Timer 类构造函数摘要 1 Ti ...

  4. input子系统基础之按键4——输入核心层源码分析

    以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 主要分析input.c文件 一.输入核心层源码分析1 1.核心模块注册:input_init函数 (1)class_r ...

  5. SDIO_WiFi驱动学习之SDIO架构介绍及源码分析

    一.引言 因为WiFi驱动比较复杂,所以WiFi驱动的博客将多分几篇来写. 本篇博客主要介绍Linux下的SDIO架构及源码分析. 本文部分内容摘抄自网络,若有侵权,请联系删除. 二.SDIO WiF ...

  6. AndroidVideoCache简单使用及源码分析

    对于视频播放,如果需要用到缓存,AndroidVideoCach是一个不错的选择,该项目地址: https://github.com/danikula/AndroidVideoCache 优缺点: 优 ...

  7. android 弹簧震动动画,Android-Rebound(弹簧系统-让动画不再僵硬)的简单使用与源码分析...

    综述:Rebound 通过胡克定律,实现的一个类似"弹簧"动画效果的第三方工具包. 单独使用 Spring spring = SpringSystem.create().creat ...

  8. 5.2.4.最简单的模块源码分析3

    printk:printk内核态,printf用户态(没什么用) 打印级别内核把级别比命令行低的所有消息显示在终端(console)上.但是所有信息都会记录在printk的"ring buf ...

  9. Android基础-Facebook Rebound 弹性动画库 源码分析

    Facebook Rebound 弹性动画库 源码分析 设计的时候老是闲动画太生硬,于是找到了这个弹性动画.这个弹性动画是facebook开源的,Rebound项目地址:https://github. ...

最新文章

  1. 如何用python画数据图-用Python绘制地理图
  2. 新基建7大产业链约500家企业图谱!
  3. Java消息中间件(activeMQ)
  4. 在Ubuntu Server 12.04 LTS上搭建可远程访问的Postgresql 9.1环境
  5. 洛谷P4630 [APIO2018] Duathlon 铁人两项 【圆方树】
  6. CL_CRM_REPORT_ACCRULE_ONEORDER
  7. [Buzz.Today]2011.06.26
  8. 计算机怎么查看U盘品牌,如何查看电脑u盘使用
  9. [Leedcode][JAVA][第236题][二叉树的公共祖先][后序遍历][BFS]
  10. 响应式设计之 —— 视口
  11. 基于JavaWeb实现的研究室综合系统
  12. 分子动力学模拟需要掌握的理论、语言和软件
  13. Word未保存文档恢复
  14. GRU 详解+实战(生成汪峰感觉的歌词)
  15. Centos 7.4 防火墙关闭命令
  16. Matlab:数模13-多元回归分析模型
  17. 使用Python API实现TRT版BN/hswish/Silu等算子
  18. Cesium加载GLB和GLTF模型文件踩坑实录
  19. 想学3D建模,去哪儿学比较好
  20. python练习(4)

热门文章

  1. 【PKUSC2019】线弦图【计数】【树形DP】【分治FFT】
  2. objectdatasouce的温故
  3. 快速判断数组中每个对象同一属性值是否相同
  4. WinForm 清空界面控件值的小技巧
  5. FPGA 状态机设计
  6. 本地浏览器缓存sessionStorage(临时存储) localStorage(长期存储)的使用
  7. GreenSock (TweenMax) 动画案例(二)
  8. To install 64-bit ODBC drivers
  9. 1682: [Usaco2005 Mar]Out of Hay 干草危机
  10. 更新了一个新版本的editplus 语法文件(for nagios)