编写模块必须先声明下面两句:

#include <linux/module.h>               //这个头文件包含了许多符号与函数的定义,这些符号与函数多与加载模块有关

#include <linux/init.h>                      //这个头文件包含了你的模块初始化与清除的函数

另外,如果你的模块需要用到参数传递,那么你可能就要声明moduleparam.h这个头文件了。

再者,模块里常包含一些描述性声明,如:

MODULE_LICENSE("GPL");          // "GPL" 是指明了 这是GNU General Public License的任意版本

// “GPL v2” 是指明 这仅声明为GPL的第二版本

// "GPL and addtional"

// "Dual BSD/GPL"

// "Dual MPL/GPL"

// "Proprietary"  私有的

// 除非你的模块显式地声明一个开源版本,否则内核会默认你这是一个私有的模块(Proprietary)。

MODULE_AUTHOR                        // 声明作者

MODULE_DESCRIPTION              // 对这个模块作一个简单的描述,这个描述是"human-readable"的

MODULE_VERSION                        // 这个模块的版本

MODULE_ALIAS                               // 这个模块的别名

MODULE_DEVICE_TABLE            // 告诉用户空间这个模块支持什么样的设备

MODULE_声明可以写在模块的任何地方(但必须在函数外面),但是惯例是写在模块最后。

驱动程序的作用:

简单来说 驱动程序就是使计算机与设备通信的特殊的代码,在作单片机时候(无OS)我们自己定义接口及自定义的结构来操作相关硬件,

而在有OS的模式下我们操作的硬件是去实现对应的接口(这些接口是已定义好的,我们需要实现这些接口)而无需自己定义接口,这样既能正确的控制设备。

又能很好的维护(如果需要升级驱动,上边的应用程序不需要改变)

驱动分类:

  1. 字符设备:能够像字节流(类似文件)一样被访问的设备(至少实现open, close, read ,write等功能)
  2. 快设备:    用户空间接口与字符设备相同, 内部实与字符设备完全不同(可以被随即访问,一般在类UNIX系统中快设备的读取每次只能读一整块在linux可以操作任意字节)
  3. 网络设备:网络通路通过网络设备形成,能够与主机交换数据的设备

内核功能划分:

  1. 进程管理(PM):进程的创建与撤销,在单个或者多个CPU上实现多进程的抽象
  2. 内存管理(MM):管理内存分配及回收的策略
  3. 文件系统(FS/VFS): Linux 非常依赖于文件系统,内核在没有结构的硬件系统上构造结文件系统,而文件抽象在整个系统中会广泛使用,Linux支持多种文件系统类型
  4. 设备控制:驱动程序,操控硬件以及相应总线设备
  5. 网络(NET): 在网络接口于应用程序之间传输数据。

好了 理论行得东西介绍的差不多了,下边说点有用的,内核的驱动可以做成模块在需要的时候装载,在不需要的时候卸载
我们在编写用户程序的时候总喜欢从编写hello world 写起 , 在内核驱动模块也是一样,下边是一个hello_world的一个模块

  1. //hello_world.c
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. MODULE_LICENSE("GPL");
  5. static int hello_init(void)
  6. {
  7. printk(KERN_ALERT "hello module\n");
  8. return 0;
  9. }
  10. static void hello_exit(void)
  11. {
  12. printk(KERN_ALERT "hello module exit\n");
  13. }
  14. module_init(hello_init);
  15. module_exit(hello_exit);

以及对应的Makefile

  1. ifneq ($(KERNELRELEASE),)
  2. # call from kernel build system
  3. obj-m   := hello_world.o
  4. #if we need more than one source code to build the module
  5. #we should use the variable below:  example: modules-objs := file1.o file2.o
  6. modules-objs :=
  7. else
  8. #kernel PTAH
  9. KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  10. PWD       := $(shell pwd)
  11. modules:
  12. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  13. endif
  14. clean:
  15. rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

有几点与用户空间程序不同的地方

  1. 模块程序没有main函数(那么程序入口在哪里?)
  2. 打印函数使用的printk 而不是用户空间的printf 而且使用方式不一样
  3. 模块的编译不是通常的方式
  4. 头文件不是常见的那些头文件
  5. 以及编译之后不会产生可执行文件,而是 .ko 文件
    ...

模块没有main函数,在装载模块 insmod 时会调用module_init注册的函数 此处为hello_init
在模块卸载remod时 会调用module_exit注册的函数 此处为hello_exit
在module_init 注册的函数主要是进行初始化,分配内存, 注册设备等
而module_exit中注册的函数与之相反, 设备注销, 释放内存等
具体的编译模块的Makefile我在另一篇文章中有说到 此处不再赘述
内核的打印函数使用printk去打印信息, printk不支持浮点类型, 在printk中可以加入信息级别有7中

  1. #define KERN_EMERG    "<0>"    /* system is unusable */
  2. #define KERN_ALERT    "<1>"    /* action must be taken immediately */
  3. #define KERN_CRIT     "<2>"    /* critical conditions */
  4. #define KERN_ERR      "<3>"    /* error conditions */
  5. #define KERN_WARNING  "<4>"    /* warning conditions */
  6. #define KERN_NOTICE   "<5>"    /* normal but significant */
  7. #define KERN_INFO     "<6>"    /* informational */
  8. #define KERN_DEBUG    "<7>"    /* debug-level messages */

对应与不同的错误等级 选择不懂的option, 并做不同的处理, 小于一定等级的信息会直接打印到终端(非X-window下的终端),可以使用dmesg来查看全部的打印信息
编译内核的头文件是在/lib/modules/$(shell uname -r)/build/include下得,而不是用户模式下得/usr/include
编译后不会生产可执行文件,会生成一个.ko的文件
使用insmod xxx.ko去装载模块
使用lsmod去查看已装载的模块
使用rmmod xxx 去卸载相应模块(卸载是不带.ko)

http://blog.csdn.net/jshazk1989/article/details/6918828

linux驱动(一)的更多相关文章

  1. Linux代码的重用与强行卸载Linux驱动

    (一)Linux代码的重用 重用=静态重用(将要重用的代码放到其他的文件的头文件中声明)+动态重用(使用另外一个Linux驱动中的资源,例如函数.变量.宏等) 1.编译是由多个文件组成的Linux驱动 ...

  2. Linux驱动学习之常用的模块操作命令

    1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...

  3. Linux驱动学习之驱动开发准备工作

    一.开启驱动开发之路 1.驱动开发的准备工作 (1)正常运行linux系统的开发板.要求开发板中的linux的zImage必须是自己编译的,不能是别人编译的.原因在于在安装模块的时候会进行安全性校验 ...

  4. Linux驱动学习之什么是驱动?

    一.什么是驱动? 1: 驱动一词的字面意思 2: 物理上的驱动 3: 硬件中的驱动 4: linux内核驱动.软件层面上的驱动广义上是指:这一段代码操作了硬件去动,所以这一段代码就叫硬件的驱动程序. ...

  5. 嵌入式Linux驱动开发日记

    嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...

  6. linux驱动程序设计的硬件基础,王明学learn

    linux驱动程序设计的硬件基础(一) 本章讲总结学习linux设备程序设计的硬件基础. 一.处理器 1.1通用处理器 通用处理器(GPP)并不针对特定的应用领域进行体系结构和指令集的优化,它们具有一 ...

  7. linux驱动初探之杂项设备(控制两个GPIO口)

    关键字:linux驱动.杂项设备.GPIO 此驱动程序控制了外接的两个二极管,二极管是低电平有效. 上一篇博客中已经介绍了linux驱动程序的编写流程,这篇博客算是前一篇的提高篇,也是下一篇博客(JN ...

  8. linux驱动初探之字符驱动

    关键字:字符驱动.动态生成设备节点.helloworld linux驱动编程,个人觉得第一件事就是配置好平台文件,这里以字符设备,也就是传说中的helloworld为例~ 此驱动程序基于linux3. ...

  9. Linux驱动之HelloWorld

    最近看android的一些源码,里面有一些功能是用驱动实现的.于是就兴起看了一些驱动相关的东西,准备日后深入.这没有技术含量的水文,仅作为日后的备忘吧. 系统使用的是ubuntu 12.0.04,内核 ...

  10. linux 驱动学习笔记01--Linux 内核的编译

    由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...

随机推荐

  1. 教程-Delphi调用C# WEBSERVICE(二)

    第二步:将webserivce的WSDL导入到该dll工程中,如何导,方法至少有两种,我说简单的一种:  file->new->other->WebService->WSDL ...

  2. [HAOI2012] 容易题

    有一个数列A已知对于所有的A[i]都是1~n的自然数,并且知道对于一些A[i]不能取哪些值,我们定义一个数列的积为该数列所有元素的乘积,要求你求出所有可能的数列的积的和 mod 1000000007的 ...

  3. DoctorNote医生处方笔记开发记录

    1.开发背景 一个开诊所的中医朋友,希望我能给他开发一个记录病人姓名和处方的Android手机app,以便查询病人每次就诊信息,比如上一次的处方,以前他要找个病人上一次的就诊处方,几乎要翻遍一叠厚厚的 ...

  4. Windows环境下安装Ionic

    1. 首先要安装node环境,Ionic的安装和后续的许多前端工具的安装都依赖于node的包管理器npm. nodeJs环境的安装很简单,去官网下载最新版的NodeJs直接安装即可.      Nod ...

  5. 通达OA 小飞鱼工作流在线培训教程文件夹及意见征集

    最近通达OA技术交流群有不少朋友反映说表单设计这块 改动样式的问题,这块须要html和css的改动.本来最近正好要在工作流这块准备做一个系列的课程,都是基础的设置主要是给刚接触工作流的朋友用的,大家有 ...

  6. leetcode每日解题思路 221 Maximal Square

    问题描述: 题目链接:221 Maximal Square 问题找解决的是给出一个M*N的矩阵, 只有'1', '0',两种元素: 需要你从中找出 由'1'组成的最大正方形.恩, 就是这样. 我们看到 ...

  7. 对Cookie进行增删改查

    public class CookieServletDemo extends HttpServlet { public void doGet(HttpServletRequest request, H ...

  8. Modify the average program to promote for intergers repeatedly.stop when a nagetive number is entere

    #include<stdio.h> int main(void) { intcount ,sum,aninterger; printf("enterthe interger an ...

  9. RedHat6.1(64bit)安装JDK

    今天在服务器上装JDK1.5,费了不少力气,记录下来以供参考 服务器安装的操作系统为Red Hat 6.1(x86) [123@123 bin]$ cat /etc/redhat-release Re ...

  10. JVM中的Stack和Heap

    Stack: 是内存指令区.Java基本数据类型,Java指令代码,常量都保存在stack中,方法是指令也保存在stack中. 由于stack是内存是顺序分配,而且定长,不存在内存回收问题.存取速度快 ...