写一个最小字符设备驱动
理论看再多不如自己 insmod 一次。下面是一个能加载、能读、能在 dmesg 里看到日志的字符设备驱动,去掉了一切非必要的东西。
驱动代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#define DEV_NAME "hello"
static int major;
static const char *msg = "hello from kernel\n";
static ssize_t hello_read(struct file *f, char __user *buf,
size_t len, loff_t *off)
{
size_t n = strlen(msg);
if (*off >= n) return 0;
if (len > n - *off) len = n - *off;
if (copy_to_user(buf, msg + *off, len)) return -EFAULT;
*off += len;
return len;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = hello_read,
};
static int __init hello_init(void)
{
major = register_chrdev(0, DEV_NAME, &fops);
if (major < 0) return major;
pr_info("hello: registered major %d\n", major);
return 0;
}
static void __exit hello_exit(void)
{
unregister_chrdev(major, DEV_NAME);
pr_info("hello: unloaded\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m := hello.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
编译与加载
apt install -y linux-headers-$(uname -r) build-essential
make
insmod hello.ko
dmesg | tail -n 2
grep hello /proc/devices
mknod /dev/hello c <major> 0
cat /dev/hello
rmmod hello
要点:register_chrdev(0, ...) 让内核动态分配主设备号;必须用 copy_to_user;read 要正确处理 *off。生产代码会用 cdev + device_create 让 udev 自动建节点,最小版先把流程跑通即可。