dirvt char / platform / module / drm

写一个最小字符设备驱动

2026-06-10 · char

理论看再多不如自己 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 自动建节点,最小版先把流程跑通即可。

← index