驱动学习--1
内核模块
内核文件中实现多种功能的组件很多,要是都编译进内核,会出
现以两个问题
1,生成的内核会很大
2,如果要修改某个功能,将不得不重新编译内核
模块的机制
特点:
1,模块本身不被编译进内核,从控制内核的大小
2,模块一旦被加载,它就和内核中的其他部分完全一样
最简单的Linux内核模块示例
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello World enter/n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Heloo World exit/n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_AUTHOR("Periscope");
MODULE_DESCRIPTION("A simply Hello Module");
MODULE_ALIAS("a simplest module");
保存为hello.c
模块的编译
Makefile内容如下
obj-m := hello.o
[root@Hunt-PC dri]# make -C /usr/src/kernels/2.6.27.5-
117.fc10.i686/ M=$(pwd) modules
make: Entering directory `/usr/src/kernels/2.6.27.5-
117.fc10.i686'
CC [M] /work/mypro/dri/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /work/mypro/dri/hello.mod.o
LD [M] /work/mypro/dri/hello.ko
make: Leaving directory `/usr/src/kernels/2.6.27.5-
117.fc10.i686'
[root@Hunt-PC dri]# ls
hello.c hello.mod.c hello.o Module.markers
Module.symvers
hello.ko hello.mod.o Makefile modules.order
目前我不清楚上面的编译选项的意思
用如下命令时会出现找不到头文件的错误,而上面的编译命令好
像进入了Fedora的内核源码文件夹当中
加载模块
insmod ./hello.ko
未知原因,不打印那行输出????
查看
[root@Hunt-PC dri]# lsmod
Module Size Used by
hello 5376 0
fuse 49436 2
sco 12932 2
..........
卸载模块 rmmod hello
注意:
模块的几个组成部分
1,模块的加载函数(必须)
否则通过insmod或modprobe命令时无法加载,那模块还有什么用
,加载函数会自动被内核执行,完成模块的初始化工作
2,模块的卸载函数(必须)
3,模块许可证声明(必须)
如果不声明加载时会收到内核被污染的警告
4模块参数(可选)
被加载时传递给它自己,这本身是对应模块的内部全局变量
5,模块导出符号(可选)
symbol对应函数或变量,这样其他模块就可使用本模块中的变量
和函数。
6,模块作者信息(可选)
假设驱动写好后文件名为test.c
编译命令为:
gcc -O2 -DMODULE -D__KERNEL__ -c test.ko test.c
如果有多个文件,每个文件按上面命令编译后用下面的命令金链
接
ld - r file1.ko file1.lo -o modulename
当然可以写成Makefile的形式,推荐使用。
加载模块
insmod -f test.ko -f 表示强制加载,比较危险,这里举例
查看
cat /proc/devices
卸载
rmmod test 设备名即可
创建设备文件节点
mknod /dev/test c major minor
最简单的字符型设备驱动程序
Linux驱动的基本组成部分
1,包涵的头文件
2,驱动的加载和卸载函数
3,字符设备驱动的file_operations结构体中的成员函数实现
其主要的工作就是编写子函数,并填充file_opearations的各个
域
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <asm/segment.h>
unsigned int test_major = 0;
static int read_test(struct inode *node, struct file
*file,char *buf, int count)
{
int left;
if (verify_aera(VERIFY_WRITE,buf,count)==-EFAULT)
return -EFAULT;
for(left = count;left>0;left--)
{
__put_user(1,buf,1);
buf++;
}
return count;
}
static int write_test(struct inode *inode,struct file
*file,const charr *buf,int count)
{
return count;
}
static int open_test(struct inode *inode,struct file
*file)
{
MOD_INC_USE_COUNT;
return 0;
}
static void release_test(struct inode *inode,struct file
*flie)
{
MOD_DEC_USE_COUNT;
}
struct file_operations test_fops = {
NULL,
read_test,
write_test,
NULL,
NULL,
NULL,
NULL,
open_test,
release_test,
NULL,
NULL,
};
int init_module(void)
{
int result;
result = register_chrdev(0, "test", &test_fops);
if(result<0)
{ printk(KERN_INFO "test:can't get major
number/n");
return result;
}
if(test_major==0)
test_major=result;
return 0;
}
void cleanup_module(void)
{
unregister_chrdev(test_major,"test");
}
一大堆错误,看不懂了。。。。
测试程序
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int testdev;
int i;
char buf[10];
testdev = open("/dev/test",O_RDWR);
if ( testdev == -1 )
{
printf("Cann't open file /n");
exit(0);
}
read(testdev,buf,10);
for (i = 0; i < 10;i++)
printf("%d/n",buf[i]);
close(testdev);
}
编译运行,看看是不是打印出全1 ?
以上只是一个简单的演示。真正实用的驱动程序要复杂的多
,要处理如中断,DMA,I/O port等问题。这些才是真正的难点
。