温馨提示×

linux驱动怎样编写

小樊
39
2026-09-15 18:44:31
栏目: 智能运维

编写 Linux 驱动通常分为字符设备驱动、块设备驱动、网络设备驱动三大类,最常见、最适合入门的是字符设备驱动。下面我以字符设备驱动为例,给你一个**从零到可加载模块(KO)**的完整思路和示例。


一、开发前准备

1. 系统环境

  • Linux 系统(Ubuntu / CentOS / 嵌入式 Linux)
  • 已安装内核头文件
# Ubuntu
sudo apt install linux-headers-$(uname -r)

2. 驱动形式

  • 内核模块(.ko):可动态加载/卸载(推荐初学者)
  • 编译进内核(复杂,不推荐入门)

二、Linux 驱动基本结构

一个最简单的字符设备驱动包含:

  1. 模块入口 / 出口
  2. 文件操作结构体 file_operations
  3. 设备号(主设备号 + 次设备号)
  4. 设备注册 / 注销

三、最简单字符设备驱动示例

1. 驱动代码(hello_drv.c)

#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");

四、编写 Makefile

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 卸载模块

八、下一步学什么?

  1. 设备树(Device Tree)(嵌入式必学)
  2. platform 驱动模型
  3. ioctl 接口
  4. 中断 / 定时器
  5. sysfs / procfs

如果你愿意,我可以:

  • 给你树莓派 / 正点原子 / 香橙派的驱动示例
  • 讲 platform + device tree 实战
  • 帮你写一个LED / 按键 / I2C / SPI 驱动

你现在是入门学习还是项目实战?

0 踩