Linux 设备驱动的第一个例子 。

Hello World


Linux 设备驱动的第一个例子 。

一. 源程序( hello.c )

 

  1. #include <linux/init.h>

  2. #include <linux/module.h>

  3. MODULE_LICENSE("Dual BSD/GPL");

  4. static int hello_init(void)

  5. {

  6. printk(KERN_ALERT "Hello, world/n");

  7. return 0;

  8. }

  9. static void hello_exit(void)

  10. {

  11. printk(KERN_ALERT "Goodbye, cruel world/n");

  12. }

  13. module_init(hello_init);

  14. module_exit(hello_exit);

(1) moudle.h
包含了大量加载模块需要的函数和符号的定义.
     (2) init.h
来指定你的初始化和清理函数
    
(3) MODULE_LICENSE("GPL");指定代码使用哪个许可
          
内核认识的特定许可有, 
               
"GPL"( 适用 GNU 通用公共许可的任何版本
), 
               
"GPL v2"( 只适用 GPL 版本 2
), 
               
"GPL and additional
rights", 
               
"Dual
BSD/GPL", 
               
"Dual
MPL/GPL", 
               
"Proprietary".
   
(4) 除此之外还可以包含模块的其他描述性定义
         
MODULE_AUTHOR ( 声明谁编写了模块
), 
         
MODULE_DESCRIPION( 一个人可读的关于模块做什么的声明 ), MODULE_VERSION (
一个代码修订版本号),
         
MODULE_ALIAS ( 模块为人所知的另一个名子
), 
         
MODULE_DEVICE_TABLE ( 来告知用户空间, 模块支持那些设备).
    (5) static int
hello_init(void)
            
初始化函数应当声明成静态的,
          static
void
hello_exit(void) 
              
清理函数, 它注销接口, 在模块被去除之前返回所有资源给系统
   
(6) module_init(hello_init);
          
这个宏定义增加了特别的段到模块目标代码中, 表明在哪里找到模块的初始化函数. 没有这个定义,
你的初始化函数不会被调用.
        
  module_exit(hello_exit);
   
(7)printk
           
在 Linux 内核中定义并且对模块可用; 它与标准 C 库函数 printf 的行为相似. 内核需要它自己的打印函数,
因为它靠自己运行
    (8)字串 KERN_ALERT
是消息的优先级,因为使用缺省优先级的消息可能不会在任何有用的地方显示

二.Makefile文件


  1. obj-m := hello.o

  2. KERNELDR := /usr/src/linux-2.6.26

  3. PWD := $(shell pwd)

  4. modules:

  5. $(MAKE) -C $(KERNELDR) M=$(PWD) modules

  6. moduels_install:

  7. $(MAKE) -C $(KERNELDR) M=$(PWD) modules_install

  8. clean:

  9. rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions

(1)obj-m := hello.o

表明有一个模块要从目标文件 hello.o 建立. 在从目标文件建立后结果模块命名为 hello.ko。

(2)KERNELDR := /usr/src/linux-2.6.26

用来定位内核源码目录

(3)PWD := $(shell pwd)

获得当前目录路径

(4)M=$(PWD) M= 选项

使 makefile 在试图建立模块目标前, 回到你的模块源码目录

(5)$(MAKE) -C $(KERNELDR) M=$(PWD) modules

这个命令开始是改变它的目录到用 -C 选项提供的目录下( 就是说, 你的内核源码目录 ). 它在那里会发现内核的顶层 makefile. 这个 M= 选项使
makefile 在试图建立模块目标前, 回到你的模块源码目录. 这个目标, 依次地, 是指在 obj-m 变量中发现的模块列表, 在我们的例子里设成了
module.o.

(6)$(MAKE) -C $(KERNELDR) M=$(PWD)
modules_install

用于模块的安装

(7)rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c
.tmp_versions

用于make clean清除上次编译生成的文件

三. 编译与加载


注意:只有超级用户可以加载和卸载模块 .


  1. % make

  2. make[1]: Entering directory `/usr/src/linux-2.6.26‘

  3. CC [M] /home/ldd3/src/misc-modules/hello.o

  4. Building modules, stage 2.

  5. MODPOST

  6. CC /home/ldd3/src/misc-modules/hello.mod.o

  7. LD [M] /home/ldd3/src/misc-modules/hello.ko

  8. make[1]: Leaving directory `/usr/src/linux-2.6.26‘

  9. % su

  10. root# insmod ./hello.ko

  11. Hello, world

  12. root# rmmod hello

  13. Goodbye cruel world

  14. root#

1.
insmod
         
加载模块的代码段和数据段到内核,并且调用模块的初始化函数来启动所有东西.
      2.
rmmod
          如果内核认为模块还在用(
就是说, 一个程序仍然有一个打开文件对应模块输出的设备 ), 或者内核被配置成不允许模块去除,
模块去除会失败.
     3.
lsmod 
        
生成一个内核中当前加载的模块的列表. lsmod 通过读取 /proc/modules 虚拟文件工作. 当前加载的模块的信息也可在位于 /sys/module
的 sysfs 虚拟文件系统找到.

4. 前面的屏幕输出是来自一个字符控制台; 如果你从一个终端模拟器或者在窗口系统中运行 insmod 和
rmmod, 你不会在你的屏幕上看到任何东西. 消息进入了其中一个系统日志文件中, 例如 /var/log/messages (实际文件名子随 Linux
发布而变化).
     5.
vermagic.o目标文件:
        
当加载一个模块时,内核为模块检查特定处理器的配置选项,确定它们匹配运行的内核。如果模块用不同选项编译,则不会加载。出现下面内容:


  1. # insmod hello.ko

  2. Error inserting ‘./hello.ko‘:-1 Invlid module forma

查看系统日志文件(var/log/message)将发现导致模块无法加载的原因

现在应该可以跑完程序,并了解了一些Linux设备驱动最基础的知识了吧!

时间: 2024-10-13 13:24:02

Linux 设备驱动的第一个例子 。的相关文章

linux设备驱动第一篇:基础知识点

首先,我们知道驱动是内核的一部分,那么驱动在内核中到底扮演了什么角色呢? 设备驱动程序在内核中的角色:他们是一个个独立的"黑盒子",使某个特定的硬件响应一个定义良好的内部编程接口,这些接口完全隐藏了设备的工作细节.(说白了,驱动程序除了对外提供特定的接口外,任何实现细节对应用程序都是不可见的.)用户的操作通过一组标准化的调用执行,而这些调用独立于特定的驱动程序.驱动程序的任务是把这些标准化调用映射到实际硬件的设备特有操作上. 在编写驱动程序时,程序员应该特别注意下面这个概念:编写访问硬

linux设备驱动第三篇:写一个简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [plain] vie

linux设备驱动中的并发控制

并发指的是多个执行单元同时.并行被执行,而并发的执行单元对共享资源的访问则很容易导致竞态 linux内核中主要竞态1.多对称处理器的多个CPU  2.单CPU内进程与抢占它的进程 3.中断(硬中断.软中断.Tasklet.下半部)与进程之间访问共享内存资源的代码区称为“临界区”,临界区需要被以某种互斥机制加以保护,中断屏蔽.原子操作.自旋锁和信号量等是linux设备驱动中可采用的互斥途径. 这几个互斥的介绍: 1.中断屏蔽,这个主要用于单CPU,中断屏蔽将使得中断和进程之间的并发不再发生.使用方

linux设备驱动第三篇:如何写一个简单的字符设备驱动?

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [email prot

linux设备驱动归纳总结(三):3.设备驱动面向对象思想和lseek的实现【转】

本文转自自:http://blog.chinaunix.net/uid-25014876-id-59418.html linux设备驱动归纳总结(三):3.设备驱动面向对象思想和lseek的实现 一.结构体struct file和struct inode 在之前写的函数,全部是定义了一些零散的全局变量.有没有办法整合成到一个结构体当中?这样的话,看起来和用起来都比较方便.接下来就要说这方面的问题. 不过先要介绍一下除了fops以外的两个比较重要的结构体: 1)struct file 在内核中,f

linux设备驱动归纳总结(四):5.SMP下的竞态和并发

linux设备驱动归纳总结(四):5.多处理器下的竞态和并发 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 这节将在上一节的基础上介绍支持多处理器和内核抢占的内核如何避免并发.除了内核抢占和中断外,由于多处理起的缘故,它可以做到多个程序同时执行.所以,进程除了要防自己的处理器外,还要防别的处理器,这个就是这节要介绍的内容. xxxxxxxxxxxxxxxxxxxxxxx

linux设备驱动第三篇:如何实现简单的字符设备驱动

在linux设备驱动第一篇:设备驱动程序简介中简单介绍了字符驱动,本篇简单介绍如何写一个简单的字符设备驱动.本篇借鉴LDD中的源码,实现一个与硬件设备无关的字符设备驱动,仅仅操作从内核中分配的一些内存. 下面就开始学习如何写一个简单的字符设备驱动.首先我们来分解一下字符设备驱动 都有那些结构或者方法组成,也就是说实现一个可以使用的字符设备驱动我们必须做些什么工作. 1.主设备号和次设备号 对于字符设备的访问是通过文件系统中的设备名称进行的.他们通常位于/dev目录下.如下: [email pro

【转】Linux设备驱动之sysfs

Sysfs文件系统是一个类似于proc文件系统的特殊文件系统,用于将系统中的设备组织成层次结构,并向用户模式程序提供详细的内核数据结构信息. 去/sys看一看,localhost:/sys#ls /sys/block/ bus/ class/ devices/ firmware/ kernel/ module/ power/Block目录:包含所有的块设备Devices目录:包含系统所有的设备,并根据设备挂接的总线类型组织成层次结构Bus目录:包含系统中所有的总线类型Drivers目录:包括内核

Linux 设备驱动 Edition 3

原文网址:http://oss.org.cn/kernel-book/ldd3/index.html Linux 设备驱动 Edition 3 By Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman 由 quickwhale 翻译的简体中文版 V0.1.0 2006-6-2 遵循原版的版权声明. 还在完善中. 欢迎任何意见, 请给我邮件. 请发信至 quickwhale 的邮箱 <[email protected]> 版权 ©