Linux系统驱动架构概述
一、Linux驱动架构概述
Linux驱动采用分层架构和模块化设计,遵循"一切皆文件"的设计思想。
1.1 驱动类型分类
二、驱动模型核心架构
2.1 驱动模型三大组件
// 内核驱动模型核心结构
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 *);
};
2.2 设备树(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>;
};
};
};
三、字符设备驱动架构
3.1 字符设备核心结构
// 字符设备驱动完整示例
#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);
// 4. 创建设备类
char_class = class_create(THIS_MODULE, CLASS_NAME);
// 5. 创建设备文件节点
char_device = device_create(char_class, NULL, devno,
NULL, DEVICE_NAME);
return 0;
}
3.2 字符设备操作流程
四、块设备驱动架构
4.1 块设备核心结构
// 块设备驱动结构
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;
};
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; // 容量(扇区数)
};
4.2 请求队列处理
// 块设备驱动示例
static int myblk_init(void)
{
struct request_queue *queue;
struct gendisk *gd;
// 1. 分配gendisk结构
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;
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; // 网络设备操作
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. 复制数据到硬件缓冲区
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. 释放skb
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;
// 1. 分配输入设备
input_dev = input_allocate_device();
if (!input_dev)
return –ENOMEM;
// 2. 设置设备类型
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;
// 3. 设置支持的事件类型
__set_bit(EV_KEY, input_dev->evbit); // 按键事件
__set_bit(EV_REL, input_dev->evbit); // 相对事件
__set_bit(EV_ABS, input_dev->evbit); // 绝对事件
// 4. 设置支持的按键
__set_bit(BTN_LEFT, input_dev->keybit); // 左键
__set_bit(BTN_RIGHT, input_dev->keybit); // 右键
__set_bit(BTN_MIDDLE, input_dev->keybit); // 中键
// 5. 设置绝对坐标范围
input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
input_set_abs_params(input_dev, ABS_Y, 0, 767, 0, 0);
// 6. 注册设备
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,
},
};
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驱动定义
static int mydev_probe(struct platform_device *pdev)
{
struct resource *res;
void __iomem *base;
int irq;
// 1. 获取资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = ioremap(res->start, resource_size(res));
irq = platform_get_irq(pdev, 0);
// 2. 获取平台数据
struct mydev_platform_data *pdata = dev_get_platdata(&pdev->dev);
// 3. 初始化硬件
// …
return 0;
}
static int mydev_remove(struct platform_device *pdev)
{
// 清理资源
return 0;
}
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驱动示例
// I2C设备结构
struct i2c_client {
unsigned short flags; // 标志
unsigned short addr; // 7位地址
char name[I2C_NAME_SIZE]; // 设备名
struct i2c_adapter *adapter; // 适配器
struct device dev; // 设备结构
int irq; // 中断号
};
// 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,
};
// 从设备树获取I2C设备
static const struct of_device_id my_i2c_of_match[] = {
{ .compatible = "vendor,my-i2c-device" },
{},
};
MODULE_DEVICE_TABLE(of, my_i2c_of_match);
// 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);
}
九、设备树与驱动匹配
9.1 设备树节点示例
设备树是描述硬件的结构化数据,以下是一个完整的设备树节点示例,包含了一个带自定义参数的I2C设备:
// 设备树示例 – 包含I2C设备节点
/
compatible = "mycompany,myboard";
i2c@12340000 {
compatible = "mycompany,i2c";
reg = <0x12340000 0x1000>;
interrupts = <0 42 0>;
#address-cells = <1>;
#size-cells = <0>;
// 带自定义参数的I2C设备
mydevice@50 {
compatible = "vendor,my-device";
reg = <0x50>; // I2C设备地址
interrupt-parent = <&gpio>;
interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
clock-frequency = <100000>; // I2C时钟频率
vendor,enable-gpio = <&gpio 16 GPIO_ACTIVE_HIGH>;
vendor,led-polarity = <0>; // 自定义属性
vendor,config-data = <0x01 0x02 0x03 0x04>; // 数组属性
};
};
};
9.2 驱动与设备树匹配机制
驱动通过设备树匹配表与硬件设备建立关联:
// 设备树匹配表定义
static const struct of_device_id my_device_of_match[] = {
{ .compatible = "vendor,my-device", .data = &my_device_data },
{}, // 终止条目
};
MODULE_DEVICE_TABLE(of, my_device_of_match);
// 驱动结构体 – 关联设备树匹配表
static struct i2c_driver my_device_driver = {
.driver = {
.name = "my-device",
.owner = THIS_MODULE,
.of_match_table = my_device_of_match, // 设备树匹配表
},
.probe = my_device_probe,
.remove = my_device_remove,
.id_table = my_device_id,
};
// 或者Platform驱动的设备树关联
static struct platform_driver my_platform_driver = {
.probe = my_platform_probe,
.remove = my_platform_remove,
.driver = {
.name = "my-platform-device",
.owner = THIS_MODULE,
.of_match_table = my_platform_of_match, // 设备树匹配表
},
};
9.3 Platform驱动probe函数获取设备树参数
以下示例展示了如何在Platform驱动的probe函数中获取设备树参数:
// Platform设备私有数据
struct my_platform_dev {
void __iomem *base;
int irq;
u32 clock_freq;
bool led_polarity;
};
static int my_platform_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct my_platform_dev *dev;
struct resource *res;
u32 enable_pin;
int ret;
// 分配私有数据
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) {
return –ENOMEM;
}
platform_set_drvdata(pdev, dev);
// 获取内存资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dev->base)) {
return PTR_ERR(dev->base);
}
// 获取中断资源
dev->irq = platform_get_irq(pdev, 0);
// 从设备树获取参数
if (np) {
// 获取整数参数 – 时钟频率
ret = of_property_read_u32(np, "clock-frequency", &dev->clock_freq);
if (ret) {
dev_warn(&pdev->dev, "Using default clock frequency\\n");
dev->clock_freq = 100000; // 默认值
}
// 获取GPIO引脚
ret = of_property_read_u8(np, "vendor,enable-gpio", &enable_pin);
if (ret) {
dev_err(&pdev->dev, "Missing enable-gpio property\\n");
return –EINVAL;
}
// 获取布尔值参数
dev->led_polarity = of_property_read_bool(np, "vendor,led-polarity");
// 获取字符串参数
const char *mode;
ret = of_property_read_string(np, "vendor,mode", &mode);
if (ret == 0) {
dev_info(&pdev->dev, "Operation mode: %s\\n", mode);
}
// 获取数组参数
u32 config_data[4];
ret = of_property_read_u32_array(np, "vendor,config-data", config_data, 4);
if (ret == 0) {
dev_info(&pdev->dev, "Config data: %#x %#x %#x %#x\\n",
config_data[0], config_data[1], config_data[2], config_data[3]);
}
}
// 使用获取的参数初始化硬件
// …
dev_info(&pdev->dev, "Platform device probed successfully\\n");
return 0;
}
9.4 I2C驱动probe函数获取设备树参数
以下示例展示了如何在I2C驱动的probe函数中获取设备树参数:
// I2C设备私有数据
struct my_i2c_dev {
struct i2c_client *client;
int reset_gpio;
bool wakeup_supported;
};
// 寄存器定义
#define INTERRUPT_CONFIG_REG 0x0C
static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct device_node *np = client->dev.of_node;
struct my_i2c_dev *dev;
u8 int_config;
int ret;
// 分配私有数据
dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) {
return –ENOMEM;
}
dev->client = client;
i2c_set_clientdata(client, dev);
// 从设备树获取参数
if (np) {
// 获取中断配置
ret = of_property_read_u8(np, "vendor,interrupt-config", &int_config);
if (ret) {
dev_warn(&client->dev, "Using default interrupt config\\n");
int_config = 0x01; // 默认配置
}
// 检查是否支持唤醒功能
dev->wakeup_supported = of_property_read_bool(np, "wakeup-source");
if (dev->wakeup_supported) {
device_init_wakeup(&client->dev, true);
dev_info(&client->dev, "Wakeup functionality enabled\\n");
}
// 获取GPIO配置
if (of_find_property(np, "vendor,reset-gpio", NULL)) {
dev->reset_gpio = of_get_named_gpio(np, "vendor,reset-gpio", 0);
if (gpio_is_valid(dev->reset_gpio)) {
ret = devm_gpio_request_one(&client->dev, dev->reset_gpio,
GPIOF_OUT_INIT_HIGH, "my_i2c_reset");
if (ret) {
dev_err(&client->dev, "Failed to request reset GPIO\\n");
return ret;
}
}
}
}
// 使用获取的参数初始化设备
ret = i2c_smbus_write_byte_data(client, INTERRUPT_CONFIG_REG, int_config);
if (ret < 0) {
dev_err(&client->dev, "Failed to configure interrupt\\n");
return ret;
}
// 注册中断
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, my_i2c_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, dev);
if (ret) {
dev_err(&client->dev, "Failed to request interrupt\\n");
return ret;
}
}
dev_info(&client->dev, "I2C device probed successfully\\n");
return 0;
}
// I2C中断处理函数
static irqreturn_t my_i2c_irq_thread(int irq, void *dev_id)
{
struct my_i2c_dev *dev = dev_id;
// 中断处理逻辑
return IRQ_HANDLED;
}
9.5 设备树匹配与参数获取的最佳实践
十、驱动模型注册流程
十一、驱动框架高级特性
11.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,
};
11.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;
}
11.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,
IRQF_SHARED | IRQF_TRIGGER_RISING,
"mydev", dev);
return ret;
}
十二、驱动调试与测试
12.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
// 通过procfs调试
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;
}
// 通过debugfs调试
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驱动架构特点
这个架构设计使得Linux能够支持从嵌入式设备到服务器、从简单字符设备到复杂网络设备的广泛硬件平台




