2025-03-13
在Linux内核中,miscdevice是一种用于简化字符设备驱动注册的机制。它适用于那些不需要主设备号的简单设备驱动。miscdevice使用一个固定的主设备号(10),开发者只需指定次设备号即可。
固定主设备号:miscdevice使用主设备号10,开发者只需关注次设备号。
简化注册:通过misc_register()和misc_deregister()函数,简化了设备驱动的注册和注销过程。
自动创建设备节点:注册后,内核会自动在/dev目录下创建设备节点。
// simple.c
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/minmax.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#define MAX_SIZE 256
static char data[MAX_SIZE];
static size_t data_len;
static int _open(struct inode *inode, struct file *file) {
pr_info("simple_open\n");
pr_info("device numbers: %d %d\n", imajor(inode), iminor(inode));
if (file->f_mode & FMODE_READ) {
pr_info("open file\n");
}
if (file->f_mode & FMODE_WRITE) {
pr_info("write file\n");
}
return 0;
}
static int _close(struct inode *inode, struct file *file) {
pr_info("simple_close\n");
return 0;
}
static ssize_t _write(struct file *file, const char __user *user_buffer,
size_t user_len, loff_t *ppos) {
int status;
pr_info("simple_write\n");
data_len = min(user_len, MAX_SIZE);
status = copy_from_user(data, user_buffer, data_len);
if (status) {
pr_err("copy_from_user error\n");
return -status;
}
return data_len;
}
static ssize_t _read(struct file *file, char __user *user_buffer,
size_t user_len, loff_t *ppos) {
int status, len;
pr_info("simple_read\n");
len = min(user_len, data_len);
status = copy_to_user(user_buffer, data, len);
if (status) {
pr_err("copy_to_user error\n");
return -status;
}
return len;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = _read,
.write = _write,
.open = _open,
.release = _close,
};
static struct miscdevice my_device = {
.name = "testdev",
.minor = MISC_DYNAMIC_MINOR,
.fops = &fops,
.mode = 0666,
};
static int __init simple_init(void) {
int status = 0;
pr_info("simple_init\n");
status = misc_register(&my_device);
if (status) {
pr_err("misc_register error\n");
return -status;
}
return 0;
}
static void __exit simple_exit(void) {
pr_info("simple_exit\n");
misc_deregister(&my_device);
}
module_init(simple_init);
module_exit(simple_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("heng30");
MODULE_VERSION("v0.0.1");
MODULE_DESCRIPTION("A simple kernel module");
#!/bin/sh
top-dir = $(shell pwd)
kernel-version = $(shell uname -r)
kernel-dir ?= /lib/modules/$(kernel-version)/build
obj-m += simple.o
all:
make -C $(kernel-dir) modules M=$(top-dir)
clean:
rm -f *.o *.ko *.mod *.mod.c *.order *.symvers *.dtbo
make -C $(kernel-dir) clean m=$(top-dir)
编译程序:make
安装驱动:insmod simple.ko
查看设备文件:ls -al /dev/testdev
crw-rw-rw- 1 root root 10, 120 Mar 13 12:10 /dev/testdev
写入数据:echo "hello" > /dev/testdev
读取数据:head -n 1 /dev/testdev
移除驱动:rmmod simple.ko