1202 字
6 分钟
平台设备驱动框架
2025-01-27
无标签

一、代码结构解析#

1. 设备结构体定义(核心数据结构)#

c

复制

struct xxx_dev { // 自定义设备结构体

struct cdev cdev;        // 内嵌字符设备结构体

/\* 可扩展其他成员:如 GPIO 编号、锁、缓冲区等 \*/

};

struct xxx_dev xxxdev; // 全局设备实例

  • 作用:描述设备的属性和状态,将字符设备 (cdev) 与平台驱动关联。

  • 扩展性:可添加硬件资源(如 GPIO)、同步机制(如互斥锁)等成员。


2. 字符设备操作函数#

c

复制

// 打开设备

static int xxx_open (struct inode *inode, struct file *filp) {

// 示例代码未实现具体操作,实际可能需要:

// - 初始化硬件(如配置 GPIO 方向)

// - 分配私有数据并关联到 filp->private\_data

return 0;

}

// 写入设备

static ssize_t xxx_write (struct file *filp, const char __user *buf,

                     size\_t cnt, loff\_t \*offt) {

// 示例代码未实现具体操作,实际可能需要:

// - 从用户空间复制数据(copy\_from\_user)

// - 控制硬件(如点亮 LED)

return 0;

}

// 文件操作集

static struct file_operations xxx_fops = {

.owner \= THIS\_MODULE,

.open \= xxx\_open,

.write \= xxx\_write,

// 可添加更多操作:. read, .release, .ioctl 等

};

  • 关键点:通过文件接口(如 /dev/xxx)暴露设备功能。

  • 用户空间交互openwrite 等函数是用户调用 open()write() 系统调用的内核入口。


3. 平台驱动核心逻辑#

c

复制

// Probe 函数:驱动与设备匹配成功后调用

static int xxx_probe (struct platform_device *pdev) {

// 1. 初始化字符设备

cdev\_init (&xxxdev. cdev, &xxx\_fops);

cdev\_add (&xxxdev. cdev, dev, 1); // 需补充设备号 (dev) 分配逻辑

// 2. 获取硬件资源(示例未实现,实际需添加):
// struct resource \*res = platform\_get\_resource(pdev, IORESOURCE\_MEM, 0);
// int irq = platform\_get\_irq(pdev, 0);

// 3. 创建设备节点(示例未实现,需补充):
// device\_create(class, NULL, dev, NULL, "xxx");

return 0;

}

// Remove 函数:驱动卸载或设备移除时调用

static int xxx_remove (struct platform_device *pdev) {

cdev\_del (&xxxdev. cdev); // 删除字符设备

// 需补充资源释放:如释放内存、GPIO、中断等

return 0;

}

// 设备树匹配表

static const struct of_device_id xxx_of_match[] = {

{ .compatible \= "xxx-gpio" }, // 必须与设备树中的 compatible 属性一致

{ /\* Sentinel \*/ }

};

// 平台驱动结构体

static struct platform_driver xxx_driver = {

.driver \= {

    .name \= "xxx",              // 驱动名称(与设备树无关,用于旧式匹配)

    .of\_match\_table \= xxx\_of\_match, // 设备树匹配表

},

.probe \= xxx\_probe,

.remove \= xxx\_remove,

};

  • 关键点

    • 设备树匹配:通过 .compatible 字段与设备树节点绑定。

    • 资源管理:实际开发中需在 probe 中调用 platform_get_resource 获取内存、中断等资源。

    • 设备节点创建:需补充 class_createdevice_create 逻辑以生成 /dev/xxx 节点。


4. 模块加载与卸载#

c

复制

// 模块初始化

static int __init xxxdriver_init (void) {

return platform\_driver\_register (&xxx\_driver);

}

// 模块卸载

static void __exit xxxdriver_exit (void) {

platform\_driver\_unregister (&xxx\_driver);

}

module_init (xxxdriver_init);

module_exit (xxxdriver_exit);

MODULE_LICENSE (“GPL”);

MODULE_AUTHOR (“zuozhongkai”);

  • 注册流程platform_driver_register 将驱动注册到平台总线。

  • 自动匹配:内核自动调用 probe 函数匹配设备。


二、执行流程分析#

1. 驱动加载阶段#

  1. 模块加载:执行 insmodmodprobe 加载驱动。

  2. 注册平台驱动platform_driver_register(&xxx_driver)

  3. 总线匹配:内核遍历已注册的平台设备,检查设备树节点的 .compatible 是否匹配 xxx_of_match

  4. 执行 Probe:匹配成功后调用 xxx_probe 函数:

    • 初始化字符设备(cdev_initcdev_add)。

    • 获取硬件资源(如寄存器地址、中断号)。

    • 创建设备节点(需补充 device_create)。

2. 用户空间操作#

  • 打开设备:用户调用 open("/dev/xxx") → 触发内核调用 xxx_open

  • 写入设备:用户调用 write() → 触发内核调用 xxx_write,实际控制硬件。

3. 驱动卸载阶段#

  1. 模块卸载:执行 rmmod 卸载驱动。

  2. 调用 Remove:内核调用 xxx_remove 函数:

    • 删除字符设备(cdev_del)。

    • 释放资源(如内存、中断、GPIO)。


三、关键改进点(示例代码缺失部分)#

1. 设备号分配与节点创建#

需补充以下逻辑:

c

复制

// 在模块初始化或 probe 函数中:

dev_t devno = MKDEV (major, minor); // 动态或静态分配设备号

alloc_chrdev_region (&devno, 0, 1, “xxx”); // 动态分配

cdev_add (&xxxdev. cdev, devno, 1);

// 创建设备类与节点

struct class *class = class_create (THIS_MODULE, “xxx_class”);

device_create (class, NULL, devno, NULL, “xxx”);

2. 硬件资源获取#

probe 函数中添加资源解析:

c

复制

struct resource *res = platform_get_resource (pdev, IORESOURCE_MEM, 0);

void __iomem *base = devm_ioremap_resource (&pdev->dev, res); // 映射寄存器

int irq = platform_get_irq (pdev, 0);

request_irq (irq, irq_handler, IRQF_TRIGGER_RISING, “xxx”, NULL);

3. 错误处理#

检查关键函数返回值:

c

复制

if (cdev_add (&xxxdev. cdev, devno, 1) < 0) {

printk (KERN\_ERR "Failed to add cdev\\n");

return \-EFAULT;

}


四、总结#

  • 代码定位:这是一个平台驱动与字符设备驱动结合的框架,适合通过设备树管理硬件资源,并通过文件接口暴露设备功能。

  • 核心流程:驱动匹配 → 资源获取 → 字符设备注册 → 用户空间交互。

  • 实际开发:需补充设备号分配、资源管理、错误处理和并发控制逻辑。

平台设备驱动框架
https://scudays.github.io/posts/embedded-linux/平台设备驱动框架/
作者
Days
发布于
2025-01-27
许可协议
CC BY-NC-SA 4.0