Linux 平台驱动程序和普通设备驱动程序有什么区别?

2024-10-24 08:50:00
admin
原创
84
摘要:问题描述:之前我曾假设:平台驱动程序适用于片上设备。正常的设备驱动程序适用于与处理器芯片接口的设备。在遇到一个 i2c 驱动程序之前...但在这里,我正在阅读定义为平台驱动程序的多功能 i2c 驱动程序。我浏览过https://www.kernel.org/doc/Documentation/driver-m...

问题描述:

之前我曾假设:

  • 平台驱动程序适用于片上设备。

  • 正常的设备驱动程序适用于与处理器芯片接口的设备。

在遇到一个 i2c 驱动程序之前...但在这里,我正在阅读定义为平台驱动程序的多功能 i2c 驱动程序。我浏览过https://www.kernel.org/doc/Documentation/driver-model/platform.txt。但仍然无法清楚地得出结论,即如何定义驱动程序,例如针对片上设备以及接口设备。

请有人解释一下。


解决方案 1:

您的参考资料很好,但缺少对平台设备的定义。 LWN上有一个。 我们可以从此页面学到什么:

  1. 平台设备本质上是不可发现的,即硬件无法对软件说“嘿!我在!”kernel/Documentation/i2c/instantiating-devices 。典型的例子是 i2c 设备,状态:

与 PCI 或 USB 设备不同,I2C 设备不是在硬件级别(运行时)枚举的。相反,软件必须知道(在编译时)每个 I2C 总线段上连接了哪些设备。因此 USB 和 PCI 不是平台设备。

  1. 平台设备通过匹配名称绑定到驱动程序,

  2. 平台设备应在系统启动的早期阶段进行注册。因为它们通常对系统(平台)的其余部分及其驱动程序至关重要。

因此,基本上,“它是平台设备还是标准设备? ”这个问题更多的是它使用哪种总线的问题。要使用特定的平台设备,您必须:

  1. 注册一个将管理此设备的平台驱动程序。它应该定义一个唯一的名称,

  2. 注册您的平台设备,定义与驱动程序相同的名称。

平台驱动程序适用于片上设备。

不正确(理论上如此,但实际上如此)。i2c 设备不是片上设备,而是平台设备,因为它们不可被发现。我们也可以认为片上设备是普通设备。例如:现代 x86 处理器上的集成 PCI GPU 芯片。它是可被发现的,因此不是平台设备。

正常的设备驱动程序适用于与处理器芯片接口的设备。在遇到一个 i2c 驱动程序之前。

不对。许多普通设备都与处理器连接,但不是通过 i2c 总线。例如:USB 鼠标。

[编辑]就您而言,请查看drivers/usb/host/ohci-pnx4008.c,这是一个 USB 主机控制器平台设备(此处 USB 主机控制器不可发现,而连接到它的 USB 设备可以发现)。它是由board 文件( arch/arm/mach-pnx4008/core.c:pnx4008_init) 注册的平台设备。在其探测功能中,它使用 将其 i2c 设备注册到总线i2c_register_driver。我们可以推断 USB 主机控制器芯片组通过 i2c 总线与 CPU通信。

为什么是这种架构?因为一方面,该设备可以被视为一个裸 i2c 设备,为系统提供一些功能。另一方面,它是一个 USB 主机功能设备。它需要注册到 USB 堆栈(usb_create_hcd)。因此,仅探测 i2c 是不够的。请查看Documentation/i2c/instantiating-devices

解决方案 2:

最小模块代码示例

通过一些具体的例子,也许差异会变得更加清晰。

平台设备示例

代码:

  • 驱动程序上游

  • 最小的 QEMU 虚拟设备驱动。

  • Linux 内核上的 DTS 条目修改

进一步的集成说明位于:https: //stackoverflow.com/a/44612957/895245

查看方法:

  • 寄存器和中断地址在设备树中硬编码-M versatilepb,并与代表 SoC 的 QEMU 机器描述相匹配

  • 无法移除设备硬件(因为它是 SoC 的一部分)

  • 通过与驱动程序compatible匹配的设备树属性来选择正确的驱动程序platform_driver.name

  • platform_driver_register是主注册接口

#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>

MODULE_LICENSE("GPL");

static struct resource res;
static unsigned int irq;
static void __iomem *map;

static irqreturn_t lkmc_irq_handler(int irq, void *dev)
{
    /* TODO this 34 and not 18 as in the DTS, likely the interrupt controller moves it around.
     * Understand precisely. 34 = 18 + 16. */
    pr_info("lkmc_irq_handler irq = %d dev = %llx
", irq, *(unsigned long long *)dev);
    /* ACK the IRQ. */
    iowrite32(0x9ABCDEF0, map + 4);
    return IRQ_HANDLED;
}

static int lkmc_platform_device_probe(struct platform_device *pdev)
{
    int asdf;
    struct device *dev = &pdev->dev;
    struct device_node *np = dev->of_node;

    dev_info(dev, "probe
");

    /* Play with our custom poperty. */
    if (of_property_read_u32(np, "lkmc-asdf", &asdf) ) {
        dev_err(dev, "of_property_read_u32
");
        return -EINVAL;
    }
    if (asdf != 0x12345678) {
        dev_err(dev, "asdf = %llx
", (unsigned long long)asdf);
        return -EINVAL;
    }

    /* IRQ. */
    irq = irq_of_parse_and_map(dev->of_node, 0);
    if (request_irq(irq, lkmc_irq_handler, 0, "lkmc_platform_device", dev) < 0) {
        dev_err(dev, "request_irq");
        return -EINVAL;
    }
    dev_info(dev, "irq = %u
", irq);

    /* MMIO. */
    if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
        dev_err(dev, "of_address_to_resource");
        return -EINVAL;
    }
    if  (!request_mem_region(res.start, resource_size(&res), "lkmc_platform_device")) {
        dev_err(dev, "request_mem_region");
        return -EINVAL;
    }
    map = of_iomap(pdev->dev.of_node, 0);
    if (!map) {
        dev_err(dev, "of_iomap");
        return -EINVAL;
    }
    dev_info(dev, "res.start = %llx resource_size = %llx
",
            (unsigned long long)res.start, (unsigned long long)resource_size(&res));

    /* Test MMIO and IRQ. */
    iowrite32(0x12345678, map);

    return 0;
}

static int lkmc_platform_device_remove(struct platform_device *pdev)
{
    dev_info(&pdev->dev, "remove
");
    free_irq(irq, &pdev->dev);
    iounmap(map);
    release_mem_region(res.start, resource_size(&res));
    return 0;
}

static const struct of_device_id of_lkmc_platform_device_match[] = {
    { .compatible = "lkmc_platform_device", },
    {},
};

MODULE_DEVICE_TABLE(of, of_lkmc_platform_device_match);

static struct platform_driver lkmc_plaform_driver = {
    .probe      = lkmc_platform_device_probe,
    .remove     = lkmc_platform_device_remove,
    .driver     = {
        .name   = "lkmc_platform_device",
        .of_match_table = of_lkmc_platform_device_match,
        .owner = THIS_MODULE,
    },
};

static int lkmc_platform_device_init(void)
{
    pr_info("lkmc_platform_device_init
");
    return platform_driver_register(&lkmc_plaform_driver);
}

static void lkmc_platform_device_exit(void)
{
    pr_info("lkmc_platform_device_exit
");
    platform_driver_unregister(&lkmc_plaform_driver);
}

module_init(lkmc_platform_device_init)
module_exit(lkmc_platform_device_exit)

PCI 非平台设备示例

  • 驱动程序上游

  • 最小 QEMU 虚拟设备驱动

查看方法:

  • 寄存器和中断地址由 PCI 系统动态分配,不使用设备树

  • 正确的驱动程序由 PCI ID 选择vendor:deviceQEMU_VENDOR_ID, EDU_DEVICE_ID例如)。这是嵌入到每个设备中的,供应商必须确保唯一性。

  • 我们可以使用 和 插入和移除 PCI 设备,device_add edu就像device_del edu在现实生活中一样。探测不是自动的,但可以在启动后使用 进行echo 1 > /sys/bus/pci/rescan。另请参阅:为什么除了 init 之外,Linux 设备驱动程序还需要探测方法?

#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>

#define BAR 0
#define CDEV_NAME "lkmc_hw_pci_min"
#define EDU_DEVICE_ID 0x11e9
#define QEMU_VENDOR_ID 0x1234

MODULE_LICENSE("GPL");

static struct pci_device_id id_table[] = {
    { PCI_DEVICE(QEMU_VENDOR_ID, EDU_DEVICE_ID), },
    { 0, }
};
MODULE_DEVICE_TABLE(pci, id_table);
static int major;
static struct pci_dev *pdev;
static void __iomem *mmio;
static struct file_operations fops = {
    .owner   = THIS_MODULE,
};

static irqreturn_t irq_handler(int irq, void *dev)
{
    pr_info("irq_handler irq = %d dev = %d
", irq, *(int *)dev);
    iowrite32(0, mmio + 4);
    return IRQ_HANDLED;
}

static int probe(struct pci_dev *dev, const struct pci_device_id *id)
{
    pr_info("probe
");
    major = register_chrdev(0, CDEV_NAME, &fops);
    pdev = dev;
    if (pci_enable_device(dev) < 0) {
        dev_err(&(pdev->dev), "pci_enable_device
");
        goto error;
    }
    if (pci_request_region(dev, BAR, "myregion0")) {
        dev_err(&(pdev->dev), "pci_request_region
");
        goto error;
    }
    mmio = pci_iomap(pdev, BAR, pci_resource_len(pdev, BAR));
    pr_info("dev->irq = %u
", dev->irq);
    if (request_irq(dev->irq, irq_handler, IRQF_SHARED, "pci_irq_handler0", &major) < 0) {
        dev_err(&(dev->dev), "request_irq
");
        goto error;
    }
    iowrite32(0x12345678, mmio);
    return 0;
error:
    return 1;
}

static void remove(struct pci_dev *dev)
{
    pr_info("remove
");
    free_irq(dev->irq, &major);
    pci_release_region(dev, BAR);
    unregister_chrdev(major, CDEV_NAME);
}

static struct pci_driver pci_driver = {
    .name     = CDEV_NAME,
    .id_table = id_table,
    .probe    = probe,
    .remove   = remove,
};

static int myinit(void)
{
    if (pci_register_driver(&pci_driver) < 0) {
        return 1;
    }
    return 0;
}

static void myexit(void)
{
    pci_unregister_driver(&pci_driver);
}

module_init(myinit);
module_exit(myexit);
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用