快速业务通道

深入浅出Linux设备驱动编程--Linux内核模块

作者 佚名技术 来源 Linux系统 浏览 发布时间 2012-05-16
深入浅出Linux设备驱动编程--Linux内核模块 宋宝华 [email]21cnbao@21cn.com[/email] yesky 2.Linux内核模块 Linux设备驱动属于内核的一部分,Linux内核的一个模块可以以两种方式被编译和加载: (1)直接编译进Linux内核,随同Linux启动时加载; (2)编译成一个可加载和删除的模块,使用insmod加载(modprobe和insmod命令类似,但依赖于相关的配置文件),rmmod删除.这种方式控制了内核的大小,而模块一旦被插入内核,它就和内核其他部分一样. 下面我们给出一个内核模块的例子: #include <linux/module.h> //所有模块都需要的头文件 #include <linux/init.h> // init&exit相关宏 MODULE_LICENSE("GPL"); static int __init hello_init (void) 拥有帝国一切,皆有可能。欢迎访问phome.net { printk("Hello module initn"); return 0; } static void __exit hello_exit (void) { printk("Hello module exitn"); } module_init(hello_init); module_exit(hello_exit); 分析上述程序,发现一个Linux内核模块需包含模块初始化和模块卸载函数,前者在insmod的时候运行,后者在rmmod的时候运行.初始化与卸载函数在宏module_init和module_exit使用前定义,否则会出现编译错误. 程序中的MODULE_LICENSE("GPL")用于声明模块的许可证. 如果要把上述程序编译为一个运行时加载和删除的模块,则编译命令为: gcc –D__KERNEL__ -DMODULE –DLINUX –I /usr/local/src/linux2.4/include -c –o hello.o hello.c 由此可见,Linux内核模块的编译需要给gcc指示–D__KERNEL__ -DMODULE –DLINUX参数.-I选项跟着Linux内核源代码中Include目录的路径. 拥有帝国一切,皆有可能。欢迎访问phome.net下列命令将可加载hello模块: insmod ./hello.o 下列命令完成相反过程: rmmod hello 如果要将其直接编译入Linux内核,则需要将源代码文件拷贝入Linux内核源代码的相应路径里,并修改Makefile. 我们有必要补充一下Linux内核编程的一些基本知识: 内存 在Linux内核模式下,我们不能使用用户态的malloc()和free()函数申请和释放内存.进行内核编程时,最常用的内存申请和释放函数为在include/linux/kernel.h文件中声明的kmalloc()和kfree(),其原型为: void *kmalloc(unsigned int len, int priority); void kfree(void *__ptr); kmalloc的priority参数通常设置为GFP_KERNEL,如果在中断服务程序里申请内存则要用GFP_ATOMIC参数,使用GFP_KERNEL参数可能会引起睡眠,不能用于非进程上下文中(在中断中是不允许睡眠的). 内核态和用户态使用不同的内存定义,二者之间不能直接访问对方的内存.而应该使用Linux中的用户和内核态内存交互函数(这些函数在include/asm/uaccess.h中被声明): unsigned long copy_from_user(void *to, const void *from, unsigned long n); unsigned long copy_to_user (void * to, void * from, unsigned long len); 拥有帝国一切,皆有可能。欢迎访问phome.net copy_from_user、copy_to_user函数返回不能被复制的字节数,因此,如果完全复制成功,返回值为0. include/asm/uaccess.h中定义的put_user和get_user用于内核空间和用户空间的单值交互(如char、int、long). 这里给出的仅仅是关于内核中内存管理的皮毛,关于Linux内存管理的更多细节知识,我们会在本文第9节《内存与I/O操作》进行更加深入地介绍. 输出 在内核编程中,我们不能使用用户态C库函数中的printf()函数输出信息,而只能使用printk().但是,内核中printk()函数的设计目的并不是为了和用户交流,它实际上是内核的一种日志机制,用来记录下日志信息或者给出警告提示. 每个printk都会有个优先级,内核一共有8个优先级,它们都有对应的宏定义.如果未指定优先级,内核会选择默认的优先级DEFAULT_MESSAGE_LOGLEVEL.如果优先级数字比int console_loglevel变量小的话,消息就会打印到控制台上.如果syslogd和klogd守护进程在运行的话,则不管是否向控制台输出,消息都会被追加进/var/log/messages文件.klogd 只处理内核消息,syslogd 处理其他系统消息,比如应用程序. 模块参数 2.4内核下,include/linux/module.h中定义的宏MODULE_PARM(var,type) 用于向模块传递命令行参数.var为接受参数值的变量名,type为采取如下格式的字符串[min[-max]]{b,h,i,l,s}.min及max用于表示当参数为数组类型时,允许输入的数组元素的个数范围;b:byte;h:short;i:int;l:long;s:string. 在装载内核模块时,用户可以向模块传递一些参数: 拥有帝国一切,皆有可能。欢迎访问phome.netinsmod modname var=value如果用户未指定参数,var将使用模块内定义的缺省值.

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号