首页 > 系统相关 >Linux驱动开发 platform设备注册详解

Linux驱动开发 platform设备注册详解

时间:2024-10-18 09:18:24浏览次数:3  
标签:platform 详解 注册 Linux device pdev my 设备

常用的与平台设备注册相关的函数及其作用:

1. platform_device_register()

功能:用于注册平台设备到内核设备模型中。注册后,设备与相应的驱动程序绑定,驱动的 probe 函数被调用以进行初始化。

函数原型

int platform_device_register(struct platform_device *pdev);

参数

  • pdev:指向 platform_device 结构体的指针,描述了要注册的设备。

返回值

  • 成功时返回 0,失败时返回负数的错误代码。

示例

struct platform_device my_device = {
    .name = "my_device",
    .id = -1,
};
platform_device_register(&my_device);

2. platform_device_unregister()

功能:用于注销已注册的平台设备,释放相关的资源。

函数原型

void platform_device_unregister(struct platform_device *pdev);

参数

  • pdev:指向 platform_device 结构体的指针,描述要注销的设备。

示例

platform_device_unregister(&my_device);

3. platform_device_alloc()

功能:动态分配一个平台设备结构体,并初始化其 nameid 字段。它为设备结构体的内存分配提供便利。

函数原型

struct platform_device *platform_device_alloc(const char *name, int id);

参数

  • name:设备的名称。
  • id:设备的唯一 ID。如果不需要指定 ID,可以使用 -1

返回值

  • 成功时返回指向 platform_device 结构体的指针,失败时返回 NULL

示例

struct platform_device *pdev;
pdev = platform_device_alloc("my_device", -1);
if (!pdev)
    return -ENOMEM;

4. platform_device_add()

功能:将已经通过 platform_device_alloc() 分配的设备添加到内核设备模型中。

函数原型

int platform_device_add(struct platform_device *pdev);

参数

  • pdev:指向 platform_device 结构体的指针,描述要添加的设备。

返回值

  • 成功时返回 0,失败时返回负数的错误代码。

示例

struct platform_device *pdev;
pdev = platform_device_alloc("my_device", -1);
if (pdev) {
    platform_device_add(pdev);
}

5. platform_device_put()

功能:减少设备的引用计数,并在设备的引用计数为 0 时释放设备的内存。这通常与 platform_device_alloc()platform_device_add() 一起使用。

函数原型

void platform_device_put(struct platform_device *pdev);

参数

  • pdev:指向 platform_device 结构体的指针,描述要释放的设备。

示例

platform_device_put(pdev);

6. platform_device_add_resources()

功能:为平台设备添加资源(如内存地址、I/O 地址、中断号等)。这些资源在设备注册时传递给驱动程序的 probe 函数。

函数原型

int platform_device_add_resources(struct platform_device *pdev, const struct resource *res, unsigned int num);

参数

  • pdev:指向 platform_device 结构体的指针。
  • res:指向 resource 结构体数组的指针,定义了设备的资源。
  • num:资源的数量。

返回值

  • 成功时返回 0,失败时返回负数的错误代码。

示例

struct resource my_resources[] = {
    [0] = {
        .start = 0x10000000,
        .end   = 0x100000ff,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = 5,
        .end   = 5,
        .flags = IORESOURCE_IRQ,
    },
};

platform_device_add_resources(pdev, my_resources, ARRAY_SIZE(my_resources));

7. platform_device_add_data()

功能:为平台设备添加私有数据。这些数据在 probe 函数中通过 platform_get_drvdata() 函数获取,方便驱动程序使用。

函数原型

int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);

参数

  • pdev:指向 platform_device 结构体的指针。
  • data:指向要添加的数据。
  • size:数据的大小。

返回值

  • 成功时返回 0,失败时返回负数的错误代码。

示例

struct my_data {
    int value;
} my_device_data = {
    .value = 42,
};

platform_device_add_data(pdev, &my_device_data, sizeof(my_device_data));

小结

  • 设备的注册与注销platform_device_register()platform_device_unregister() 是用于设备注册和移除的主要函数。
  • 资源管理:使用 platform_device_add_resources() 来为设备添加硬件资源,比如内存或中断。
  • 动态分配platform_device_alloc()platform_device_add() 提供了灵活的动态分配方式,而 platform_device_put() 则用于释放资源。
  • 数据传递platform_device_add_data() 可以将私有数据与设备一起传递给驱动程序,以便在 probe 函数中使用。

Linux platform 设备注册详解

在 Linux 驱动开发中,平台设备(Platform Device)通常用于描述嵌入式系统中那些没有标准总线(如 PCI、USB 等)连接的硬件设备。平台设备的注册是驱动开发的重要步骤,通过注册设备,内核可以识别并与之进行交互。平台设备的注册通常有两种方式:静态注册动态注册。下面详细介绍这两种方式,以及如何在设备树(Device Tree)中进行注册。

1. 静态注册

静态注册主要在代码中显式定义平台设备,并通过相关的 API 函数将其注册到内核中。这种方式比较适合简单的硬件或者不依赖设备树的设备。

静态注册步骤

Step 1:定义 platform_device 结构体

#include <linux/platform_device.h>

static struct platform_device my_platform_device = {
    .name = "my_platform_device",  // 设备名称,驱动会通过该名称匹配
    .id = -1,                      // 如果系统中只存在一个此类设备,使用 -1
    // 如果有资源,使用 resource 结构体进行描述
};

Step 2:注册平台设备
通过调用 platform_device_register() 函数将设备注册到内核。

static int __init my_device_init(void) {
    return platform_device_register(&my_platform_device);
}
module_init(my_device_init);

Step 3:卸载平台设备
在卸载模块时,调用 platform_device_unregister() 函数注销设备。

static void __exit my_device_exit(void) {
    platform_device_unregister(&my_platform_device);
}
module_exit(my_device_exit);

完整示例

#include <linux/module.h>
#include <linux/platform_device.h>

static struct platform_device my_platform_device = {
    .name = "my_platform_device",
    .id = -1,
};

static int __init my_device_init(void) {
    return platform_device_register(&my_platform_device);
}

static void __exit my_device_exit(void) {
    platform_device_unregister(&my_platform_device);
}

module_init(my_device_init);
module_exit(my_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Author");
MODULE_DESCRIPTION("A simple Platform Device example");

2. 动态注册

动态注册方式通常用于需要灵活地在运行时添加或删除设备。使用 platform_device_alloc()platform_device_add() 函数动态分配和添加设备。

动态注册步骤

Step 1:动态分配 platform_device 结构体

struct platform_device *pdev;
pdev = platform_device_alloc("my_platform_device", -1);
if (!pdev)
    return -ENOMEM;

Step 2:注册平台设备

int ret = platform_device_add(pdev);
if (ret) {
    platform_device_put(pdev);  // 注册失败时,释放资源
    return ret;
}

Step 3:注销和释放设备
在模块卸载时,调用 platform_device_unregister() 注销设备,并使用 platform_device_put() 释放资源。

platform_device_unregister(pdev);
platform_device_put(pdev);

3. 设备树(Device Tree)中的平台设备注册

在嵌入式系统中,使用设备树来定义平台设备是一种标准做法。设备树用于描述硬件资源,并由内核解析以匹配对应的驱动程序。设备树方式相比于静态注册更加灵活,因为它将硬件信息与代码分离。

设备树注册步骤

Step 1:在设备树中定义设备

设备树中的 compatible 字段用于描述设备类型,驱动程序通过 compatible 与设备匹配。

设备树(.dts 文件)片段:

my_device@10000000 {
    compatible = "my_vendor,my_device";  // 匹配驱动程序中的 compatible
    reg = <0x10000000 0x1000>;           // 设备的寄存器地址范围
    interrupt-parent = <&intc>;          // 中断控制器
    interrupts = <5>;                    // 中断号
};

Step 2:在驱动中匹配设备

在驱动中,使用 of_match_table 来匹配设备树中的 compatible 字段。

static const struct of_device_id my_of_match[] = {
    { .compatible = "my_vendor,my_device", },
    {},
};
MODULE_DEVICE_TABLE(of, my_of_match);

Step 3:驱动与设备树匹配

驱动的 platform_driver 结构体中包含了 of_match_table,用于将设备树中的设备与驱动匹配。

static struct platform_driver my_driver = {
    .probe = my_probe,
    .remove = my_remove,
    .driver = {
        .name = "my_platform_device",
        .of_match_table = my_of_match,
        .owner = THIS_MODULE,
    },
};

module_platform_driver(my_driver);

4. 资源管理

Platform 设备可能需要管理的资源包括内存映射寄存器、I/O 端口和中断号等。资源可以通过设备树或者 resource 结构体在设备注册时传递给驱动程序。

资源定义和注册

Step 1:定义资源

如果不使用设备树,可以手动定义 resource 结构体来描述设备的资源。

static struct resource my_resources[] = {
    [0] = {
        .start = 0x10000000,
        .end   = 0x100000ff,
        .flags = IORESOURCE_MEM,
    },
    [1] = {
        .start = 5,
        .end   = 5,
        .flags = IORESOURCE_IRQ,
    },
};

Step 2:在设备注册时添加资源

pdev = platform_device_alloc("my_platform_device", -1);
if (!pdev)
    return -ENOMEM;

ret = platform_device_add_resources(pdev, my_resources, ARRAY_SIZE(my_resources));
if (ret) {
    platform_device_put(pdev);
    return ret;
}

5. 加载和卸载驱动

在注册设备之后,需要加载驱动程序以匹配并初始化设备。驱动程序编译为内核模块后,可以通过 insmodmodprobe 命令加载:

  • 加载驱动
    sudo insmod my_platform_driver.ko
    
  • 卸载驱动
    sudo rmmod my_platform_driver
    

总结

  • 静态注册:适合简单的设备,直接在代码中定义并注册 platform_device 结构体。
  • 动态注册:更加灵活,适用于需要在运行时动态添加或删除设备的场景。
  • 设备树注册:常用于嵌入式系统,通过设备树描述硬件资源,驱动通过 compatible 字段与设备匹配。
  • 资源管理:无论是通过代码或设备树注册平台设备,都需要正确管理设备的硬件资源。

通过合理选择注册方式,可以更有效地开发和管理 Linux 平台设备驱动。

标签:platform,详解,注册,Linux,device,pdev,my,设备
From: https://blog.csdn.net/weixin_44251074/article/details/142875074

相关文章

  • 【Linux线程】Linux多线程编程:深入理解线程互斥与同步机制
    ......
  • 预科02》:Markdown语法详解
    Markdown学习标题三级标题四级标题标题语法:#空格标题名回车(几极标题就用几个#号)字体hello,word!hello,word!hello,word!hello,word!(前面后面加*号鼠标点一下可以看见)引用选择狂神说学java走向人生巅峰!(语法:>空格描述)分割线语法---或者***......
  • [Redis] 在Linux中安装Redis并连接图形化工具详细过程(附下载链接)
    前言安装Redis之前应该在虚拟机中安装Linux系统,这里使用centos7版本[linux]在VMware中安装linux、文件下载及详细安装过程(附下载链接)-CSDN博客安装Linux后,更换yum源为阿里云并安装gcc依赖[Linux]CentOS7替换yum源为阿里云并安装gcc详细过程(附下载链接)-CSDN博客redis-6......
  • Java之Lambda表达式详解
    一、Lambda表达式的概念与特点Lambda表达式是Java8引入的一个重要特性,它提供了一种简洁、优雅的方式来处理集合、过滤、映射等操作。Lambda表达式可以看做是匿名函数,它允许开发者以更简洁的方式声明匿名函数。Lambda表达式的基本语法由箭头指示符“->”表示,它将参数与函数......
  • [转]Learn Power Platform Power Apps Dataverse Write a plug-in
    Learn PowerPlatform PowerApps Dataverse Writeaplug-inInthisarticleIPlugininterfacePluginBaseabstractclassServicesyoucanuseinyourcodePuttingitalltogetherShow2moreYoucancreate plug-ins byusingoneofthefollowingmetho......
  • linux ps和kill指令
    目录ps命令kill指令:示例:补充:管道的概念管道的概念管道的用途示例在Linux系统中,ps和kill是两个非常常用的命令,用于管理和终止进程。ps命令ps命令用于显示当前系统中的进程状态。它可以提供关于系统进程的详细信息,如进程ID、运行用户、CPU使用率、内存使用......
  • 公网Linux环境搭建frp实现内网穿透
    前提:本实验为一台ubuntu22操作系统云主机脚本适用于安装平台:CentOS、Debian、UbuntuFRP项目地址:https://github.com/fatedier/frpFRP一键脚本地址:https://github.com/MvsCode/frps-onekey 1、FRP服务器端一键安装脚本(脚本在本文最后有,如果在服务器上无法获取到下面的instal......
  • Linux环境下Matplotlib绘图中文乱码问题
    问题:如图所示,中文乱码1.准备ttf字体文件:路径: C:\Windows\Fonts例如楷体:simkai.ttf2.查看当前环境的matplot字体路径:importmatplotlibprint(matplotlib.matplotlib_fname())运行结果:/home/3kyou/.local/lib/python3.7/site-packages/matplotlib/mpl-data/matplotlibr......
  • 【数据结构】之链表详解
    链表是一种常用的数据结构,它是一种线性数据结构,但与数组不同,它并非连续存储数据,而是通过指针将数据节点连接起来。每个节点都包含数据域和指向下一个节点的指针域。这种结构赋予链表独特的优势和局限性,使其在某些场景下优于数组,在另一些场景下则相对逊色。本文将深入探讨链表,包......
  • 【最新】Kali linux零基础学习教程(超详细),从下载、安装到使用
    一、下载kaliLinux镜像https://www.kali.org/get-kali/#kali-installer-images二、开始安装kalilinux基于Debianlinux,所以选择的时候安装你下载的iso镜像来选择32位或者64位。1、选择图形化安装2、中文简体,continue继续----中国—汉语3、网络自动配置失败,问题......