#include <linux/init.h>
#include <linux/module.h>
static int __init mydriver_init(void)
{
printk(KERN_INFO "Driver loaded\n");
return 0;
}
static void __exit mydriver_exit(void)
{
printk(KERN_INFO "Driver unloaded\n");
}
module_init(mydriver_init);
module_exit(mydriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Sample Linux Driver");
#include <linux/fs.h>
#include <linux/cdev.h>
static int mydriver_open(struct inode *inode, struct file *file)
{
// 设备打开处理
return 0;
}
static ssize_t mydriver_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
// 读取设备数据
return 0;
}
static ssize_t mydriver_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
// 写入设备数据
return count;
}
static struct file_operations mydriver_fops = {
.owner = THIS_MODULE,
.open = mydriver_open,
.read = mydriver_read,
.write = mydriver_write,
// 其他操作...
};
static dev_t dev_num;
static struct cdev mydriver_cdev;
static int __init mydriver_init(void)
{
// 分配设备号
alloc_chrdev_region(&dev_num, 0, 1, "mydriver");
// 初始化cdev结构
cdev_init(&mydriver_cdev, &mydriver_fops);
mydriver_cdev.owner = THIS_MODULE;
// 添加cdev到系统
cdev_add(&mydriver_cdev, dev_num, 1);
return 0;
}
#include <linux/ioctl.h>
#define MYDRIVER_IOC_MAGIC 'k'
#define MYDRIVER_IOCTL_CMD1 _IO(MYDRIVER_IOC_MAGIC, 0)
#define MYDRIVER_IOCTL_CMD2 _IOR(MYDRIVER_IOC_MAGIC, 1, int)
static long mydriver_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case MYDRIVER_IOCTL_CMD1:
// 处理命令1
break;
case MYDRIVER_IOCTL_CMD2:
// 处理命令2
break;
default:
return -ENOTTY;
}
return 0;
}
#include <linux/proc_fs.h>
static struct proc_dir_entry *proc_entry;
static int mydriver_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "Driver information...\n");
return 0;
}
static int mydriver_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, mydriver_proc_show, NULL);
}
static const struct file_operations mydriver_proc_fops = {
.owner = THIS_MODULE,
.open = mydriver_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
// 在init函数中添加
proc_entry = proc_create("mydriver", 0, NULL, &mydriver_proc_fops);
printk - 内核日志输出
printk(KERN_DEBUG "Debug message: value=%d\n", value);
动态调试(dynamic debug)
// 在代码中使用
pr_debug("Debug message\n");
// 运行时启用
echo 'file mydriver.c +p' > /sys/kernel/debug/dynamic_debug/control
内核Oops分析
dmesg
查看日志编译时添加调试信息
EXTRA_CFLAGS += -g
加载符号表
gdb vmlinux
(gdb) add-symbol-file mydriver.ko 0xffffffffa0000000
设置断点
(gdb) b mydriver_init
probe module("mydriver").function("mydriver_read") {
printf("mydriver_read called\n");
print_stack();
}
# 启用函数跟踪
echo function > /sys/kernel/debug/tracing/current_tracer
echo mydriver_* > /sys/kernel/debug/tracing/set_ftrace_filter
echo 1 > /sys/kernel/debug/tracing/tracing_on
# 运行测试
# ...
# 查看跟踪结果
cat /sys/kernel/debug/tracing/trace
modinfo mydriver.ko
dmesg | tail
kmemleak
工具检测KASAN
内核配置检测使用适当的锁机制:
static DEFINE_SPINLOCK(my_lock);
spin_lock(&my_lock);
// 临界区代码
spin_unlock(&my_lock);
c
void __iomem *regs = ioremap(phys_addr, size);
iowrite32(value, regs + offset);
iounmap(regs);
scripts/checkpatch.pl
)通过以上方法和工具,您可以有效地开发和调试Linux设备驱动程序。记住,驱动开发需要特别小心,因为错误可能导致系统不稳定或数据损坏。