楼主: 12312312315
132 0

[作业] Linux系统驱动架构概述 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

80%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
30 点
帖子
2
精华
0
在线时间
0 小时
注册时间
2018-7-30
最后登录
2018-7-30

楼主
12312312315 发表于 2025-12-12 17:10:46 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

Linux驱动架构解析

Linux系统中的设备驱动程序采用分层与模块化的设计理念,遵循“一切皆文件”的核心哲学。这种设计不仅提升了代码的可维护性,也增强了系统的扩展能力。

主要驱动类型

根据设备功能和数据传输方式的不同,Linux驱动可分为以下几类:

  • 字符设备驱动:以字节为单位进行数据读写,如串口、键盘等。
  • 块设备驱动:支持随机访问,通常用于存储设备,如硬盘、SD卡。
  • 网络设备驱动:负责网络数据包的收发,如以太网卡、Wi-Fi模块。
  • 杂项设备驱动:用于管理主次设备号固定的特殊设备,简化注册流程。
  • 平台设备驱动:针对片上外设(SoC内部资源)的抽象驱动模型。
  • 总线设备驱动:涵盖PCI、USB、I2C、SPI等物理或逻辑总线上的设备控制。

驱动模型的核心组成

Linux内核通过三大关键结构实现设备与驱动的统一管理:

struct bus_type {        // 总线类型定义
    const char *name;
    int (*match)(struct device *, struct device_driver *);
    int (*probe)(struct device *);
    int (*remove)(struct device *);
};
struct device {          // 设备实例描述
    struct device *parent;
    struct kobject kobj;
    const char *init_name;
    struct device_driver *driver;
    struct bus_type *bus;
    void *platform_data;
};
struct device_driver {   // 驱动程序结构
    const char *name;
    struct bus_type *bus;
    struct module *owner;
    int (*probe)(struct device *);
    int (*remove)(struct device *);
};

这三者共同构建了设备-总线-驱动的匹配机制,实现了设备热插拔、自动绑定等功能。

设备树(Device Tree)的支持机制

现代嵌入式系统广泛使用设备树来描述硬件配置,避免驱动与具体平台硬编码绑定。以下是一个典型的设备树片段示例:

/ {
    compatible = "mycompany,myboard";
    cpus {
        cpu@0 {
            compatible = "arm,cortex-a53";
        };
    };
    memory@80000000 {
        reg = <0x80000000 0x20000000>;
    };
    i2c@12340000 {
        compatible = "mycompany,i2c";
        reg = <0x12340000 0x1000>;
        #address-cells = <1>;
        #size-cells = <0>;
        eeprom@50 {
            compatible = "atmel,24c256";
            reg = <0x50>;
        };
    };
};

字符设备驱动的实现架构

作为最常见的驱动类型之一,字符设备驱动需完成设备号分配、cdev注册及用户空间接口对接等工作。其基本框架如下:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define DEVICE_NAME "mychardev"
#define CLASS_NAME  "mycharclass"
#define DEVICE_COUNT 1

static int major_number = 0;
static struct class* char_class  = NULL;
static struct device* char_device = NULL;
static struct cdev my_cdev;

// 文件操作接口定义
static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = mydev_open,
    .release = mydev_release,
    .read = mydev_read,
    .write = mydev_write,
    .unlocked_ioctl = mydev_ioctl,
};

// 驱动初始化函数
static int __init mydev_init(void)
{
    dev_t devno;
    int ret;

    // 1. 动态申请设备号
    ret = alloc_chrdev_region(&devno, 0, DEVICE_COUNT, DEVICE_NAME);
    major_number = MAJOR(devno);

    // 2. 初始化cdev结构
    cdev_init(&my_cdev, &fops);
    my_cdev.owner = THIS_MODULE;

    // 3. 将cdev添加到内核系统中
    ret = cdev_add(&my_cdev, devno, DEVICE_COUNT);
    if (ret) {
        unregister_chrdev_region(devno, DEVICE_COUNT);
        return ret;
    }
    
    // 创建设备节点(可选)
    char_class = class_create(THIS_MODULE, CLASS_NAME);
    char_device = device_create(char_class, NULL, devno, NULL, DEVICE_NAME);

    return 0;
}

该结构确保了用户程序可通过标准系统调用(open/read/write/ioctl等)与底层硬件交互。

3.2 字符设备操作流程


四、块设备驱动架构

4.1 块设备核心结构

struct gendisk {
    int major;                    // 主设备号
    int first_minor;              // 第一个次设备号
    int minors;                   // 次设备号数量
    char disk_name[DISK_NAME_LEN]; // 磁盘名称
    struct block_device_operations *fops; // 操作函数集合
    struct request_queue *queue;  // 请求队列
    void *private_data;           // 私有数据指针
    sector_t capacity;            // 设备容量(以扇区为单位)
};

struct block_device_operations {
    int (*open)(struct block_device *, fmode_t);
    void (*release)(struct gendisk *, fmode_t);
    int (*ioctl)(struct block_device *, fmode_t, unsigned, unsigned long);
    int (*getgeo)(struct block_device *, struct hd_geometry *);
    struct module *owner;
};

4.2 请求队列处理

// 块设备初始化示例
static int myblk_init(void)
{
    struct request_queue *queue;
    struct gendisk *gd;

    // 1. 分配gendisk结构体,支持MYDEV_MINORS个分区
    gd = alloc_disk(MYDEV_MINORS);

    // 2. 初始化请求队列,并绑定请求处理函数与锁
    queue = blk_init_queue(mydev_request, &mydev_lock);

    // 3. 配置gendisk各项参数
    gd->major = MYDEV_MAJOR;
    gd->first_minor = 0;
    gd->fops = &mydev_fops;
    gd->queue = queue;
    gd->private_data = mydev_data;
    snprintf(gd->disk_name, 32, "myblk%d", 0);
    set_capacity(gd, mydev_size_sectors);

    // 4. 将磁盘注册到内核系统中
    add_disk(gd);

    return 0;
}

// 请求处理函数实现
static void mydev_request(struct request_queue *q)
{
    struct request *req;

    // 循环获取并处理每一个I/O请求
    while ((req = blk_fetch_request(q)) != NULL) {

        // 非文件系统类型的请求直接结束
        if (req->cmd_type != REQ_TYPE_FS) {
            __blk_end_request_all(req, -EIO);
            continue;
        }

        // 根据读写方向调用对应处理函数
        if (rq_data_dir(req) == READ)
            mydev_read(req);
        else
            mydev_write(req);
    }
}

五、网络设备驱动架构

5.1 网络设备核心结构

// 网络设备结构体定义
struct net_device {
    char name[IFNAMSIZ];              // 网络设备名称
    unsigned long mem_end;            // 共享内存区域结束地址
    unsigned long mem_start;          // 共享内存区域起始地址
    unsigned long base_addr;          // I/O寄存器基地址
    unsigned int irq;                 // 使用的中断号
    const struct net_device_ops *netdev_ops; // 设备操作函数集
};
// 网络设备结构体关键字段定义
struct net_device {
    const struct ethtool_ops *ethtool_ops;   // ethtool操作接口
    unsigned int flags;                     // 设备状态与功能标志
    int mtu;                                // 最大传输单元配置
    unsigned char *dev_addr;                // 网络设备MAC地址指针
    struct net_device_stats stats;          // 数据收发统计信息
    void *priv;                             // 驱动私有数据区域
};

// 定义网络设备的操作函数集合
struct net_device_ops {
    int (*ndo_open)(struct net_device *dev);
    int (*ndo_stop)(struct net_device *dev);
    netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev);
    void (*ndo_tx_timeout)(struct net_device *dev);
    struct rtnl_link_stats64* (*ndo_get_stats64)(...);
    int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
    int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
};

5.2 示例:网络设备驱动实现

// 驱动模块初始化函数
static int mynet_init(void)
{
    struct net_device *dev;
    int ret;

    // 步骤1:分配网络设备结构空间,包含私有数据区
    dev = alloc_netdev(sizeof(struct mynet_priv), "eth%d", NET_NAME_UNKNOWN, ether_setup);
    if (!dev)
        return -ENOMEM;

    // 步骤2:随机生成并设置硬件MAC地址
    eth_hw_addr_random(dev);

    // 步骤3:绑定设备操作函数集
    dev->netdev_ops = &mynet_ops;
    dev->ethtool_ops = &mynet_ethtool_ops;

    // 步骤4:配置MTU及设备标志位
    dev->mtu = 1500;
    dev->flags |= IFF_NOARP;

    // 步骤5:向内核注册该网络设备
    ret = register_netdev(dev);
    if (ret) {
        free_netdev(dev);
        return ret;
    }

    return 0;
}

// 数据包发送处理函数
static netdev_tx_t mynet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    struct mynet_priv *priv = netdev_priv(dev);

    // 操作步骤1:暂停发送队列以确保独占访问
    netif_stop_queue(dev);

    // 操作步骤2:将数据包内容复制至IO映射的发送缓冲区
    memcpy_toio(priv->tx_buffer, skb->data, skb->len);

    // 操作步骤3:触发硬件开始传输
    outl(TX_START, priv->ioaddr + TX_REG);

    // 操作步骤4:更新发送统计计数
    dev->stats.tx_packets++;
    dev->stats.tx_bytes += skb->len;

    // 操作步骤5:释放套接缓冲区资源
    dev_kfree_skb(skb);

    return NETDEV_TX_OK;
}

六、输入子系统驱动架构

6.1 输入子系统核心组成结构

// 输入设备驱动代码示例
#include <linux/input.h>

struct input_dev *input_dev;
// 输入设备初始化流程 static int myinput_init(void) { int error; // 第一步:动态分配输入设备结构体 input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; // 第二步:设定设备基本信息 input_dev->name = "My Input Device"; input_dev->id.bustype = BUS_USB; input_dev->id.vendor = 0x1234; input_dev->id.product = 0x5678; input_dev->id.version = 0x0100; // 第三步:声明设备支持的事件类型
// 设置输入事件类型
__set_bit(EV_KEY, input_dev->evbit);  // 启用按键事件
__set_bit(EV_REL, input_dev->evbit);  // 启用相对坐标事件
__set_bit(EV_ABS, input_dev->evbit);  // 启用绝对坐标事件

// 配置支持的按键码
__set_bit(BTN_LEFT, input_dev->keybit);   // 支持左键
__set_bit(BTN_RIGHT, input_dev->keybit);  // 支持右键
__set_bit(BTN_MIDDLE, input_dev->keybit); // 支持中键

// 定义绝对坐标的参数范围
input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 767, 0, 0);

// 注册输入设备到系统
error = input_register_device(input_dev);
if (error) {
    input_free_device(input_dev);
    return error;
}
return 0;
}

// 事件上报函数,用于提交输入数据
static void report_input_event(int x, int y, int button)
{
    // 提交当前的绝对位置
    input_report_abs(input_dev, ABS_X, x);
    input_report_abs(input_dev, ABS_Y, y);

    // 提交按键状态信息
    input_report_key(input_dev, BTN_LEFT, button & 0x01);
    input_report_key(input_dev, BTN_RIGHT, button & 0x02);

    // 发送同步事件,标志本次上报结束
    input_sync(input_dev);
}



七、Platform总线驱动架构

7.1 Platform设备/驱动模型

// 定义Platform设备所使用的资源 static struct resource mydev_resources[] = { [0] = { .start = 0x10000000, // 内存起始物理地址 .end = 0x1000FFFF, // 内存结束地址 .flags = IORESOURCE_MEM, // 资源类型:内存 }, [1] = { .start = IRQ_NUM, // 中断号起始 .end = IRQ_NUM, // 中断号结束 .flags = IORESOURCE_IRQ, // 资源类型:中断 }, }; // 构建Platform设备实例 static struct platform_device mydev_device = { .name = "my-platform-device", // 设备名称 .id = -1, // 自动编号 .num_resources = ARRAY_SIZE(mydev_resources), // 资源数量 .resource = mydev_resources, // 指向资源数组 .dev = { .platform_data = &mydev_pdata, // 绑定平台特定数据 }, }; // Platform驱动中的probe函数实现 static int mydev_probe(struct platform_device *pdev) { struct resource *res; void __iomem *base; int irq; // 第一步:获取设备的内存资源 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = ioremap(res->start, resource_size(res)); // 获取中断资源 irq = platform_get_irq(pdev, 0); // 第二步:取得平台数据指针 struct mydev_platform_data *pdata = dev_get_platdata(&pdev->dev); // 第三步:进行硬件初始化操作 // (具体初始化代码省略) return 0; } // 驱动移除时调用的清理函数 static int mydev_remove(struct platform_device *pdev) { // 执行必要的资源释放工作 return 0; } // 注册Platform驱动结构体 static struct platform_driver mydev_driver = { .probe = mydev_probe, .remove = mydev_remove, .driver = { .name = "my-platform-device", .owner = THIS_MODULE, .of_match_table = of_match_ptr(mydev_of_match), }, };

八、I2C/SPI总线驱动架构

8.1 I2C驱动示例

struct input_dev *input_dev;
// I2C设备结构定义
struct i2c_client {
    unsigned short flags;        // 标志位信息
    unsigned short addr;         // 7位从设备地址
    char name[I2C_NAME_SIZE];    // 设备名称字段
    struct i2c_adapter *adapter; // 关联的I2C适配器指针
    struct device dev;           // 内嵌设备模型结构
    int irq;                     // 使用的中断号
};

// 驱动框架高级特性

10.1 电源管理
// 定义电源管理操作集
static const struct dev_pm_ops mydev_pm_ops = {
    .suspend = mydev_suspend,
    .resume = mydev_resume,
    .freeze = mydev_freeze,
    .thaw = mydev_thaw,
    .poweroff = mydev_poweroff,
    .restore = mydev_restore,
    .runtime_suspend = mydev_runtime_suspend,
    .runtime_resume = mydev_runtime_resume,
    .runtime_idle = mydev_runtime_idle,
};

10.3 中断处理
// 中断服务例程实现
static irqreturn_t mydev_interrupt(int irq, void *dev_id)
{
    struct mydev *dev = dev_id;
    u32 status;

    // 获取当前中断状态寄存器值
    status = readl(dev->base + INT_STATUS_REG);
    if (status & DATA_READY_INT) {
        // 触发数据处理流程
        mydev_process_data(dev);
        // 清除已响应的中断标志
        writel(DATA_READY_INT, dev->base + INT_CLEAR_REG);
        return IRQ_HANDLED;
    }
    return IRQ_NONE;
}

// 请求并注册中断线
static int mydev_request_irq(struct mydev *dev)
{
    int ret;
    ret = request_irq(dev->irq, mydev_interrupt,

九、驱动模型注册流程

// I2C驱动结构体初始化
static struct i2c_driver my_i2c_driver = {
    .driver = {
        .name = "my_i2c_device",
        .owner = THIS_MODULE,
        .of_match_table = my_i2c_of_match,
    },
    .probe = my_i2c_probe,
    .remove = my_i2c_remove,
    .id_table = my_i2c_id,
};

// 匹配设备树节点的兼容性列表
static const struct of_device_id my_i2c_of_match[] = {
    { .compatible = "vendor,my-i2c-device" },
    {},
};
MODULE_DEVICE_TABLE(of, my_i2c_of_match);

10.2 DMA支持
// 初始化DMA相关资源
static int mydev_dma_setup(struct mydev *dev)
{
    // 分配一致性内存用于DMA传输
    dev->dma_buf = dma_alloc_coherent(&pdev->dev,
                                      DMA_BUF_SIZE,
                                      &dev->dma_handle,
                                      GFP_KERNEL);

    // 配置设备支持的DMA寻址能力
    dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));

    // 申请专用DMA通道
    dev->dma_chan = dma_request_channel(mask, mydev_dma_filter, NULL);
    return 0;
}

// I2C读写操作封装函数
static int my_i2c_read_reg(struct i2c_client *client, u8 reg, u8 *val)
{
    return i2c_smbus_read_byte_data(client, reg);
}

static int my_i2c_write_reg(struct i2c_client *client, u8 reg, u8 val)
{
    return i2c_smbus_write_byte_data(client, reg, val);
}

十一、驱动调试与测试

11.1 调试方法

#define DEBUG #undef PDEBUG #ifdef DEBUG # ifdef __KERNEL__ # define PDEBUG(fmt, args...) printk(KERN_DEBUG "mydev: " fmt, ## args) # else # define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args) # endif #else # define PDEBUG(fmt, args...) #endif static int mydev_proc_show(struct seq_file *m, void *v) { seq_printf(m, "Driver Status:\n"); seq_printf(m, " Version: %s\n", DRIVER_VERSION); seq_printf(m, " Devices: %d\n", device_count); return 0; } static int __init mydev_debugfs_init(void) { struct dentry *dir; dir = debugfs_create_dir("mydev", NULL); debugfs_create_u32("debug_level", 0644, dir, &debug_level); debugfs_create_file("registers", 0444, dir, NULL, ®isters_fops); return 0; }

十二、Linux驱动架构特点总结

  • 分层架构:从硬件抽象层到驱动核心层,再到子系统层和用户接口层,形成清晰的层次结构。
  • 统一模型:采用设备-总线-驱动模型,支持热插拔机制,提升系统动态性。
  • 设备树:实现硬件描述与驱动代码的分离,增强可移植性。
  • 模块化设计:支持驱动模块的动态加载与卸载,便于开发和维护。
  • 多平台兼容:适用于x86、ARM、MIPS、PowerPC等多种处理器架构。
  • 电源管理:提供完整的电源管理框架,支持低功耗模式。
  • DMA支持:具备高效的数据传输能力,减轻CPU负担。
  • 中断处理:支持多种中断处理模式,适应不同硬件需求。
  • 同步机制:集成自旋锁、互斥锁、信号量、完成量等并发控制手段。
  • 内存管理:提供kmalloc、vmalloc以及DMA映射等灵活的内存分配方式。

该架构设计使Linux能够广泛支持从嵌入式设备到高性能服务器,涵盖从简单字符设备到复杂网络设备的多样化硬件平台。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Linux Lin compatible Operations Resources

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-20 15:31