Chinaunix首页 | 论坛 | 博客
  • 博客访问: 385849
  • 博文数量: 57
  • 博客积分: 2299
  • 博客等级: 大尉
  • 技术积分: 1109
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-27 23:12
文章分类
文章存档

2011年(4)

2010年(53)

分类: 嵌入式

2010-01-22 20:14:09

今天开始学习Linux设备驱动,一边参照天嵌手册上与硬件相关的代码,一边看刚入手不久的《LINUX设备驱动程序》第三版,刚开始避免不了学习hello world,下面就这过程说一下!
源码如下:

#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");/*告诉内核,该模块采用自由许可证*/
static int __init Hiteg_hello_init(void)
{
    printk(KERN_ALERT "Hello,world! I am gfy! I am coming!\n");

/*在终端打印出字符,KERN_ALERT定义了该消息的优先级,默认优先级是不会在终端打印出来的*/
    return 0;
}
static void __exit Hiteg_hello_exit(void)
{
    printk(KERN_ALERT "Goodbye! I will be back!\n");

/*清楚函数没有返回值,void*/
}
module_init(Hiteg_hello_init);
module_exit(Hiteg_hello_exit);

下面是Makefile,没有采用天嵌那种在内核中字符设备下面添加编译信息,而是参照《LINUX设备驱动程序》上面,根据自己的环境写的,还添加进去了删除无用文件的功能。如下:

# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := hello.o #即使不在内核目录树内编译,这句也不能省略,它告诉下面要编译的文件
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= ~/kernel/linux-2.6.25.8
PWD := $(shell pwd)
default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
        @rm -f *.o *.order *.symvers *.mod.*  #删除无用文件
        @cp -f *.ko /nfs    #拷贝到我的的主机和板子共享文件夹下
endif

好,make一下,即可在当前目录下生成hello.ko的模块,然后在板子挂载共享文件夹

[root@gfy-S3C2440 /tmp]# mount -t nfs -o nolock 192.168.0.102:/nfs /tmp/

先insmod后rmmod该模块,即可看到如下所示,

[root@gfy-S3C2440 /tmp]# insmod hello.ko
Hello, I am I am
[root@gfy-S3C2440 /tmp]# rmmod hello.ko
 I will be

总结第一个驱动程序就这样好了,下面总结一下有用的东西:摘自《LINUX设备驱动程序》

insmod
modprobe
rmmod
用户空间工具, 加载模块到运行中的内核以及去除它们.

#include
module_init(init_function);
module_exit(cleanup_function);
指定模块的初始化和清理函数的宏定义.

__init
__initdata
__exit
__exitdata
函数( __init 和 __exit )和数据 (__initdata 和 __exitdata)的标记, 只用在模块初始化或者清理时间. 为初始化所标识的项可能会在初始化完成后丢弃; 退出的项可能被丢弃如果内核没有配置模块卸载. 这些标记通过使相关的目标在可执行文件的特定的 ELF 节里被替换来工作.

#include
最重要的头文件中的一个. 这个文件包含很多驱动使用的内核 API 的定义, 包括睡眠函数和许多变量声明.

struct task_struct *current;
当前进程.
current->pid
current->comm
进程 ID 和 当前进程的命令名.

obj-m
一个 makefile 符号, 内核建立系统用来决定当前目录下的哪个模块应当被建立.

/sys/module
/proc/modules
/sys/module 是一个 sysfs 目录层次, 包含当前加载模块的信息. /proc/moudles 是旧式的, 那种信息的单个文件版本. 其中的条目包含了模块名, 每个模块占用的内存数量, 以及使用计数. 另外的字串追加到每行的末尾来指定标志, 对这个模块当前是活动的.

vermagic.o
来自内核源码目录的目标文件, 描述一个模块为之建立的环境.

#include
必需的头文件. 它必须在一个模块源码中包含.

#include
头文件, 包含在建立的内核版本信息.

LINUX_VERSION_CODE
整型宏定义,#ifdef 版本依赖有用.

EXPORT_SYMBOL (symbol);
EXPORT_SYMBOL_GPL (symbol);
宏定义, 用来输出一个符号给内核. 第 2 种形式输出没有版本信息, 第 3 种限制输出给 GPL 许可的模块.

MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);
放置文档在目标文件的模块中.

module_init(init_function);
module_exit(exit_function);
宏定义, 声明一个模块的初始化和清理函数.

#include
module_param(variable, type, perm);
宏定义, 创建模块参数, 可以被用户在模块加载时调整( 或者在启动时间, 对于内嵌代码). 类型可以是 bool, charp, int, invbool, short, ushort, uint, ulong, 或者 intarray.
#include
int printk(const char * fmt, ...);
内核代码的 printf 类似物.


阅读(1649) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~