• 如何编写一个简单的Linux驱动(一)——驱动的基本框架


    前言

      最近在学习Linux驱动,记录下自己学习的历程。

    1.驱动的基本框架

      Linux驱动的基本框架包含两部分,“模块入口、出口的注册”和“模块入口、出口函数的实现”,如下方代码。  

     1 static int __init shanwuyan_init(void)    //驱动入口函数
     2 {
     3     return 0;
     4 }
     5 
     6 static void __exit shanwuyan_exit(void)    //驱动出口函数
     7 {
     8 
     9 }
    10 
    11 module_init(shanwuyan_init);    //注册入口函数
    12 module_exit(shanwuyan_exit);    //注册出口函数

      其中,module_init()和module_exit()两个函数的作用是注册驱动的入口“shanwuyan_init”和出口“shanwuyan_exit”。加载驱动时会运行入口函数,卸载驱动时会运行出口函数。入口函数的作用是加载驱动时做一些初始化工作,比如注册设备、申请设备号、生成设备节点等等,其返回值为int类型;出口函数的作用是卸载驱动时做一些善后操作,比如注销设备、注销设备号、销毁类等等。

    2.一个基本驱动的编写

      本文的主要目的是让读者了解驱动的基本框架,我们先不实现注册设备、申请设备号、注销设备等复杂的工作。

      为了让驱动的加载和卸载工作更直观地为程序员所观察,我们可以在入口函数和出口函数中添加打印语句,这样每次加载和卸载驱动的时候,程序员都能在终端观察到相应的信息,如下方代码。  

     1 static int __init shanwuyan_init(void)    //驱动入口函数
     2 {
     3     printk(KERN_EMERG "shanwuyan_init
    ");
     4     return 0;
     5 }
     6 
     7 static void __exit shanwuyan_exit(void)    //驱动出口函数
     8 {
     9     printk(KERN_EMERG "shanwuyan_exit
    ");
    10 }

      “printk”函数是什么?说到打印,有C语言基础的读者首先想到的可能就是“printf”函数,但是“printf”只能在应用层面工作,而设备驱动是工作在内核态下的,所以“printf”不能在设备驱动中工作。在内核态下的打印函数是“printk”函数。KERN_EMERG是打印优先级,这里采用了最高优先级。

      再加上头文件以及注册用的函数,可以得到一个相对完整的代码。    

     1 /* 源代码文件名为:shanwuyan.c */
     2 #include <linux/module.h>
     3 #include <linux/kernel.h>
     4 #include <linux/init.h>
     5 #include <linux/fs.h>
     6 #include <linux/uaccess.h>
     7 
     8 static int __init shanwuyan_init(void)    //驱动入口函数
     9 {
    10     printk(KERN_EMERG "shanwuyan_init
    ");
    11     return 0;
    12 }
    13 
    14 static void __exit shanwuyan_exit(void)    //驱动出口函数
    15 {
    16     printk(KERN_EMERG "shanwuyan_exit
    ");
    17 }
    18 
    19 module_init(shanwuyan_init);    //注册入口函数
    20 module_exit(shanwuyan_exit);    //注册出口函数

      该设备驱动实现的功能是:加载驱动时打印字符串“shanwuyan_init”,卸载驱动时打印字符串“shanwuyan_exit”。

    3.Makefile文件的编写

      Makefile文件没什么可说的,代码如下(记得匹配自己的内核目录)。  

     1 #!/bin/bash
     2 
     3 obj-m += shanwuyan.o    #此处要和你的驱动源文件同名
     4 
     5 KDIR := /home/topeet/Android/iTop4412_Kernel_3.0    #这里是你的内核目录
     6 
     7 PWD ?= $(shell pwd)
     8 
     9 all:
    10     make -C $(KDIR) M=$(PWD) modules    #make操作
    11 
    12 clean:
    13     make -C $(KDIR) M=$(PWD) clean    #make clean操作

    4.应用

      编译,并加载生成的“shanwuyan.ko”文件,加载驱动和卸载驱动的命令如下。  

    1 insmod shanwuyan.ko #加载驱动
    2 rmmod shanwuyan.ko #卸载驱动,如果该命令不起作用,请用下方的命令
    3 rmmod shanwuyan    #卸载驱动

      进入到驱动文件所在的路径下,并在命令行输入加载驱动的命令“insmod shanwuyan.ko”,可以看到驱动入口函数打印出来的字符串信息“shanwuyan_init”。

      但是终端还打印了两行警告信息“shanwuyan: module license 'unspecified' taints kernel”和“Disabling lock debugging due to kernel”,这是因为我们没有在代码中加入同意开源协议,所以终端打印该信息。需要注意的是,该警告信息只有在系统启动后第一次加载驱动时才会打印,卸载掉之后,如果不重启系统,再加载驱动时就不会再打印这两行警告信息了。

      打开源文件,加入GPL开源协议,一个完整的基本驱动框架就完成了,全部代码如下。

     1 /* 源代码文件名为:shanwuyan.c */
     2 #include <linux/module.h>
     3 #include <linux/kernel.h>
     4 #include <linux/init.h>
     5 #include <linux/fs.h>
     6 #include <linux/uaccess.h>
     7 
     8 static int __init shanwuyan_init(void)    //驱动入口函数
     9 {
    10     printk(KERN_EMERG "shanwuyan_init
    ");
    11     return 0;
    12 }
    13 
    14 static void __exit shanwuyan_exit(void)    //驱动出口函数
    15 {
    16     printk(KERN_EMERG "shanwuyan_exit
    ");
    17 }
    18 
    19 module_init(shanwuyan_init);    //注册入口函数
    20 module_exit(shanwuyan_exit);    //注册出口函数
    21 
    22 MODULE_LICENSE("GPL");    //同意GPL开源协议,就不会打印警告信息了
    23 MODULE_AUTHOR("shanwuyan");    //还可以再添加上作者名称

      再次编译,重启系统,并加载驱动,这次不会再打印警告信息了,只打印了我们在入口函数中写的字符串,如下图。

      使用“rmmod shanwuyan”命令卸载驱动,出现错误,如下图。  

      这是我们需要创建文件夹“/lib/modules”,创建后再次卸载驱动,又出现了错误,如下图。

      我们按照错误信息,创建文件夹“/lib/modules/3.0.15”(根据内核版本的不同而不同),再次卸载驱动,成功,打印出来我们想要的字符串信息“shanwuyan_exit”。

      本文的全部代码在这里

  • 相关阅读:
    centos 7安装gitlab及使用
    jenkins配置自动执行sql脚本
    zabbix监控mysql主从同步
    linux服务器通过mailx邮件发送附件到指定邮箱
    监控pos收银机
    elk安装与配置
    zabbix实时监控mysql业务数据
    Build Eclipse plug-in for Hadoop
    io 一不小心 关闭不住的偶
    hdu 1059二进制优化背包问题
  • 原文地址:https://www.cnblogs.com/UnfriendlyARM/p/13629905.html
Copyright © 2020-2023  润新知