我本仁慈,奈何苍天不许
分类: LINUX
2013-12-18 18:37:00
说明:以下实验室的实验条件为:Ubuntu12.04 s5pc100(Cortex-A8)
因为模块和内核之间必须是一一对应关系才行的,即是同一模块和不同版本的内核是不匹配的,假设我的模块代码放在hello目录下.
1、先进入hello目录,编译,make(这里编译是不会通过的,但是还必须的有这一步,因为这里虽然通不过,但是在内核中会产生一些文件)
2、先编译内核。Make zImage
3、在编译模块,代码如下:
Hello.c代码:
#include
#include
#include
#include
#include
MODULE_LICENSE ("GPL");
#define DEVICE_MAJOR 250
#define DEVICE_MINOR 0
#define DEVICE_NUM 1
#define DEVICE_NAME "hello"
struct cdev *cdev; //定义字符设备指针
struct file_operations hello_fops = { //文件操作
.owner = THIS_MODULE
};
static int __init hello_init (void)
{
int ret;
dev_t dev_id = 0;
dev_id = MKDEV (DEVICE_MAJOR , DEVICE_MINOR);
ret = register_chrdev_region (dev_id, DEVICE_NUM, DEVICE_NAME);
if (ret<0) {
printk (" can't get major number %d\n", DEVICE_MAJOR);
goto err_reg_cdev;
}
cdev = cdev_alloc(); //分配空间给字符设备
if(NULL == cdev)
{
printk (" cdev_alloc fail\n");
goto err_cdev_alloc;
}
cdev_init(cdev,&hello_fops); //字符设备初始化
cdev->owner = THIS_MODULE; //THIS_MODULE 相当于c++中this ,表示该字符设备为本模块所有
cdev->ops = &hello_fops; //字符设备相关的文件操作
ret = cdev_add(cdev,dev_id,DEVICE_NUM); //添加字符设备到系统中
if(ret)
{
printk("cdev_add fail %d\n",ret);
goto err_cdev_add;
}
printk("char device register ok\n");
return 0;
//---goto 出错处理, 顺序申请,逆序释放,避免资源回收不完全(如内存泄露,这种做法很经典,这中倒序的处理错误,使上面调用时,不用写多个函数调用却能执行多个资源释放。类似于switch case函数中,只是在最后写一个break,同样的道理。
err_cdev_add:
cdev_del(cdev);
err_cdev_alloc:
unregister_chrdev_region(dev_id,DEVICE_NUM);
err_reg_cdev:
return ret;
}
static void __exit hello_exit (void)
{
dev_t dev_id = 0;
dev_id = MKDEV (DEVICE_MAJOR , DEVICE_MINOR);
if (cdev)
cdev_del (cdev);
unregister_chrdev_region (dev_id, DEVICE_NUM);
printk("char unregister ok\n");
}
module_init (hello_init);
module_exit (hello_exit);
}
Makefile代码:
ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /lib/modules/$(shell uname -r)/build //这是用于PC机上测试的
KERNELDIR ?= /home/farsight/kernel/linux-2.6.35-farsight //这是用于开发板测试的,注意这个目录是你编译开发板内核的目录
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules* a.out
else
obj-m := hello.o
endif
4、然后把刚才编译的内核烧进开发板,文件系统通过NFS挂载
5、把测试代码编译arm-none-linux-gnueabi-gcc test.c
代码如下:
#include
#include
#include
#include
#include
#include
int main (void)
{
int fd;
fd = open ("/dev/hello",O_RDWR);
if (fd < 0) {
printf("open /dev/hello fail\n");
return -1;
}
close (fd);
printf("main exit\n");
return 0;
}
6、把a.out和hello.ko拷贝进NFS中
7、把模块加载进内核,insmod hello.ko
8、配置设备节点,mknod /dev/hello c 250 0 (在代码里面设置的主设备号是250)
9、最后运行a.out,如下图:
还可以用dmesg命令查看相关信息,如下图:
这些打印信息可以参照源码查看。