一、编写驱动文件
#include <linux/init.h> // 所有模块都必须包含的头文件
#include <linux/module.h> // 一些宏定义,例如这里的KERN_INFO
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include "hello_world.h"
#define VICHIP_DEV "vichip"
static struct class *driver_class; // 定义类static dev_t vichip_device_no; // 定义设备号
// 定义结构体
struct vichip_control {
struct cdev cdev;
};
static struct vichip_control vichip;
static int vichip_open(struct inode *inode, struct file *file)
{
int ret = 0;
printk(KERN_INFO "----vichip_open----\n");
return ret;
}
static int vichip_release(struct inode *inode, struct file *file)
{
int ret = 0;
printk(KERN_INFO "----vichip_release----\n");
return ret;
}
static const struct file_operations vichip_fops = {
.owner = THIS_MODULE,
.open = vichip_open,
.release = vichip_release
};
static int __init hello_init(void)
{
int rc;
struct device *class_dev;
rc = alloc_chrdev_region(&vichip_device_no, 0, 1, VICHIP_DEV); // 动态分配设备编号
if (rc < 0) {
pr_err("alloc_chrdev_region failed %d\n", rc);
return rc;
}
driver_class = class_create(THIS_MODULE, VICHIP_DEV); // 创建类
if (IS_ERR(driver_class)) {
rc = -ENOMEM;
pr_err("class_create failed %d\n", rc);
goto exit_unreg_chrdev_region;
}
class_dev = device_create(driver_class, NULL, vichip_device_no, NULL, VICHIP_DEV); // 创建设备(这个设备属于哪一类设备)
if (IS_ERR(class_dev)) {
pr_err("class_device_create failed %d\n", rc);
rc = -ENOMEM;
goto exit_destroy_class;
}
cdev_init(&vichip.cdev, &vichip_fops); // 初始化字符设备
vichip.cdev.owner = THIS_MODULE;
rc = cdev_add(&vichip.cdev, MKDEV(MAJOR(vichip_device_no), 0), 1); // 将字符设备添加到内核中
if (rc < 0) {
pr_err("cdev_add failed %d\n", rc);
cdev_del(&vichip.cdev); // 将字符设备从内核中移除
goto exit_destroy_device;
}
printk(KERN_INFO "----hello_init rc = [%d]----\n", rc);
return rc;
exit_destroy_device:
device_destroy(driver_class, vichip_device_no); // 销毁设备
exit_destroy_class:
class_destroy(driver_class); // 销毁类
exit_unreg_chrdev_region:
unregister_chrdev_region(vichip_device_no, 1); // 注销动态分配的设备号
return rc;
}
static void __exit hello_exit(void)
{
cdev_del(&vichip.cdev);
device_destroy(driver_class, vichip_device_no);
class_destroy(driver_class);
unregister_chrdev_region(vichip_device_no, 1);
printk(KERN_INFO "----hello_exit----\n");
}
module_init(hello_init);// 用宏来指定入口,加载模块时里面的加载函数会被调用
module_exit(hello_exit);
// 模块的许可证
MODULE_LICENSE("GPL");
// 模块的作者
MODULE_AUTHOR(DRIVER_AUTHOR);
// 模块的描述
MODULE_DESCRIPTION(DRIVER_DESC);
二、头文件hello_world.h
#define DRIVER_AUTHOR "[email protected]"
#define DRIVER_DESC "A sample driver"
三、编写Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
else
obj-m := hello_world.o
endif
四、编译模块
make all
五、安装内核模块
insmod hello_world.ko
六、编写测试文件test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define DEV_NAME "/dev/vichip"
int main(int argc, char *argv[])
{
int fd = -1;
printf("------------start---------------\n");
if(fd < 0)
{
perror("open file error:");
return -1;
}
close(fd);
printf("------------end---------------\n");
}
七、编译测试文件
gcc test.c -o test
八、测试驱动程序
./test
九、测试结果
1、查看创建的类
结果:在/sys/class目录下有vichip目录。
2、查看创建的设备
结果:在/dev目录下有vichip设备文件
crw------- 1 root root 243, 0 May 9 16:42 vichip
或cat /proc/devices
243 vichip
3、查看输出的消息
dmesg
----hello_init rc = [0]----
4、卸载已安装的内核模块
rmmod hello_world
执行如下操作:
cdev_del(&vichip.cdev);
device_destroy(driver_class, vichip_device_no);
class_destroy(driver_class);
unregister_chrdev_region(vichip_device_no, 1);