er来完成内核空间到用户空间的数据拷贝。
static inline long copy_to_user(void __user *to,const void *from, unsigned long n)
static char main_buffer;
static ssize_t main_write(struct file* filp,const char __user* buffer,size_t length,loff_t * l)
{
? ? if(length!=1)? return -1;
? ? copy_from_user(&main_buffer,buffer,length);
? ? return 1;
}
下面是读的实现
static ssize_t main_read(struct file* filp,char __user * buffer,size_t length,loff_t*l)
{
? ? if(length!=1) return -1;
? ? copy_to_user(buffer,&main_buffer,length);
? ? return 1;
}
再稍稍实现一下close
static int main_close(struct inode* inode,struct file* filp)
{
? ? return 0;
}?
我们所需要的内容都已经填写完毕,我们在驱动初始化的时候调用cdev_add驱动注册到系统就行了,不过在注册之前我们要申请设备号。
static dev_t dev;
static int __init main_init(void)
{?
首先我们使用动态申请的方式申请设备号
int result=alloc_chrdev_region(&dev,0,1,MODULE_NAME);
dev就是我们申请的设备号,其中dev_t其实就是一个无符号的long型,通过调用alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *) 将申请到的设备号写入到dev中,第二个参数是子设备号从几开始,第三个参数是申请几个设备号,因为申请多个设备号是连续的,所以我们只需要知道第一个就行了。第四个参数代表我们驱动的名称。
? ? ? ? if(result<0)
? ? {
? ? ? ? printk(KERN_ALERT"device load error");
? ? ? ? return -1;
? ? }
?
然后我们再构造一下我们的接口结构体
? ? ops.owner=THIS_MODULE;
? ? ops.open=main_open;
? ? ops.release=main_close;
? ? ops.write=main_write;
? ? ops.read=main_read;
构造完之后,我们就只剩下我们最重要的一步了,就是向系统注册我们的驱动。
不过,先别急,我们注册前得先把我们的抽象驱动mydev给构造了,mydev的定义在最上面。
cdev_init(&mydev,&ops);
mydev.owner=THIS_MODULE;
这样,我们就使用了我们的ops构造了我们的抽象驱动,当我们把这个驱动添加到我们的内核里面的时候,假如内核想对这个驱动进行写的操作,就会从mydev->ops->main_write这样找到我们自己实现的写函数了。
接下来就注册我们的驱动。
? ? ? ? cdev_add(&mydev,dev,1);
? ? ? ? printk(KERN_ALERT"device load success\n");
? ? ? ? return 0;
}
至此,我们的驱动就算完成了,不过有一点,就是我们的驱动有了初始化函数了就一定还有一个清理的函数了,该函数主要在我们卸载驱动的时候会调用,module_init及module_exit主要用于声明这个驱动的入口与出口,是必须要做的一步。
static void __exit main_exit(void)
{
? ? ? ? unregister_chrdev_region(dev,1);
? ? cdev_del(&mydev);
}
module_init(main_init);
module_exit(main_exit);
?
我的Makefile是下面这样
ifeq ($(KERNELRELEASE),)
KERNELDIR?=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
modules:
? ? $(MAKE) -C $(KERNELDIR) M=$(PWD) modules -Wall
modules_install:
? ? $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install -Wall
clean:
? ? rm -rf *.0 *~ core .depend .*.cmd
? ? sudo rmmod main
? ? sudo rm /dev/main
install:
? ? sudo insmod main.ko
? ? sudo mknod /dev/main c 250 0
message:
? ? tail -n 5 /var/log/kern.log
.PHONY: modules modules_install clean
else
? ? obj-m :=main.o
endif
因为我的机器是使用ubuntu,所以在message标签下是tail -n 5 /var/log/kern.log 如果的/var/log目录下没有kern.log,那么就替换成/var/log/messages
编译
$make
因为这个Makefile的install 都是针对我自己电脑而写的,所以并不能在你电脑上保证执行make install 的正确性。还是在命令行中敲吧
sudo insmod main.ko
安装模块,然后查看/proc/devices里面main这个模块对应的设备号是多少,我的是250,所以创建设备节点时这样创建
sudo mknod /dev/main c 250 0
这样就成功把我们的驱动安装到内核里了
执行make message可以看到如下信息
tail -n 5 /var/log/kern.log
Sep 17 20:05:57 quanweiC kernel: [23536.688371] [UFW BLOCK] IN=wlan0 OUT= MAC=c0:18:85:73:a1:8e:b8:88:e3:eb:30:c3:08:00 SRC=192.168.1.103 DST=192.168.1.105 LEN=63 TOS=0x00 PREC=0x00 TTL=64 ID=2558 DF PROTO=UDP SPT=11818 DPT=26724 LEN=43
Sep 17 20:06:02 quanweiC kernel: [23541.691748] [UFW BLOCK] IN=wlan0 OUT= MAC=c0:18:85:73:a1:8e:b8:88:e3:eb:30:c3:08:00 SRC=192.168.1.103 DST=192.168.1.105 LEN=63 TOS=0x00 PREC=0x00 TTL=64 ID=3335 DF PROTO=UDP SPT=11818 DPT=26724 LEN=43
Sep 17 20:06:51 quanweiC kernel: [23590.610275] [UFW BLOCK] IN=wlan0 OUT= MAC=c0:18:85:73:a1:8e:b8:88:e3:eb:30:c3:08:00 SRC=192.168