编写 Linux 驱动通常分为字符设备驱动、块设备驱动、网络设备驱动三大类,最常见、最适合入门的是字符设备驱动。下面我以字符设备驱动为例,给你一个**从零到可加载模块(KO)**的完整思路和示例。
# Ubuntu
sudo apt install linux-headers-$(uname -r)
一个最简单的字符设备驱动包含:
file_operations#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "hello_dev"
static int major;
static struct cdev hello_cdev;
static char kernel_buf[100];
/* 打开设备 */
static int hello_open(struct inode *inode, struct file *file)
{
printk("hello_open\n");
return 0;
}
/* 读设备 */
static ssize_t hello_read(struct file *file, char __user *buf, size_t size, loff_t *off)
{
int len = strlen(kernel_buf);
copy_to_user(buf, kernel_buf, len);
return len;
}
/* 写设备 */
static ssize_t hello_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
copy_from_user(kernel_buf, buf, size);
kernel_buf[size] = '\0';
printk("write: %s\n", kernel_buf);
return size;
}
static int hello_release(struct inode *inode, struct file *file)
{
printk("hello_release\n");
return 0;
}
/* 文件操作结构体 */
static struct file_operations hello_fops = {
.owner = THIS_MODULE,
.open = hello_open,
.read = hello_read,
.write = hello_write,
.release = hello_release,
};
/* 模块加载 */
static int __init hello_init(void)
{
major = register_chrdev(0, DEVICE_NAME, &hello_fops);
printk("hello driver init, major=%d\n", major);
return 0;
}
/* 模块卸载 */
static void __exit hello_exit(void)
{
unregister_chrdev(major, DEVICE_NAME);
printk("hello driver exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("yourname");
MODULE_DESCRIPTION("Simple hello driver");
obj-m += hello_drv.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
make
sudo insmod hello_drv.ko
dmesg | tail
创建设备节点:
sudo mknod /dev/hello_dev c 主设备号 0
查看主设备号:
cat /proc/devices
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd = open("/dev/hello_dev", O_RDWR);
write(fd, "hello kernel", 12);
char buf[100];
read(fd, buf, 100);
printf("read: %s\n", buf);
close(fd);
return 0;
}
dmesg 查看 printk 输出lsmod 查看模块rmmod hello_drv 卸载模块如果你愿意,我可以:
你现在是入门学习还是项目实战?