嵌入式Linux设备驱动程序:发现硬件配置

Embedded Linux device drivers: Discovering the hardware configuration

Interfacing with Device Drivers

了解硬件配置

虚拟驱动程序演示了一个设备驱动程序的结构,但是由于它只操作内存结构,因此它缺乏与实际硬件的交互。设备驱动程序通常是用来与硬件交互的。部分原因是能够在第一时间发现硬件,记住它可能位于不同配置的不同地址。

在某些情况下,硬件本身提供信息。PCI或USB等可发现总线上的设备具有查询模式,该模式返回资源需求和唯一标识符。内核将标识符和可能的其他特征与设备驱动程序匹配,并将它们结合起来。

然而,嵌入式板上的大多数硬件块没有这样的标识符。您必须自己以设备树的形式或称为平台数据的C结构来提供信息。

在Linux的标准驱动程序模型中,设备驱动程序向相应的子系统注册:PCI、USB、开放固件(设备树)、平台设备等等。注册包括一个标识符和一个称为探测函数的回调函数,如果硬件ID和驱动程序的ID匹配,则调用该函数。对于PCI和USB,ID基于供应商和设备的产品ID;对于设备树和平台设备,它是一个名称(文本字符串)。

设备树

我在第三章中介绍了设备树,都是关于引导程序的。在这里,我想向您展示Linux设备驱动程序是如何与这些信息连接起来的。

作为一个例子,我将使用ARM多功能板,arch/ARM/boot/dts/Versatile-ab.dts公司,以太网适配器在此处定义:

net@10010000 { compatible = “smsc,lan91c111”; reg = <0x10010000 0x10000>; interrupts = <25>;};

平台数据

在没有设备树支持的情况下,有一种使用C结构描述硬件的后备方法,称为平台数据。

每个硬件由struct platform_device描述,它有一个名称和一个指向资源数组的指针。资源的类型由标志确定,这些标志包括:

IORESOURCE_MEM:这是内存区域的物理地址

IORESOURCE_IO:这是IO寄存器的物理地址或端口号

IORESOURCE_IRQ:这是中断号

下面是一个以太网控制器的平台数据示例,该数据取自arch/arm/mach versatile/core.c,为清晰起见,对其进行了编辑:

#define VERSATILE_ETH_BASE 0x10010000 #define IRQ_ETH 25 static struct resource smc91x_resources[] = { [0] = { .start = VERSATILE_ETH_BASE, .end = VERSATILE_ETH_BASE + SZ_64K - 1, .flags = IORESOURCE_MEM,},

  [1] = {       .start          = IRQ_ETH,       .end            = IRQ_ETH,       .flags          = IORESOURCE_IRQ,},

}; static struct platform_device smc91x_device = { .name = “smc91x”, .id = 0, .num_resources = ARRAY_SIZE(smc91x_resources), .resource = smc91x_resources,};

它有一个64KB的内存区和一个中断。平台数据必须在内核中注册,通常在板初始化时:

void __init versatile_init(void) { platform_device_register(&versatile_flash_device); platform_device_register(&versatile_i2c_device); platform_device_register(&smc91x_device); [ …]

将硬件与设备驱动程序链接

在上一节中,您已经看到了如何使用设备树和平台数据来描述以太网适配器。相应的驱动程序代码在drivers/net/ethernet/smsc/smc91x.c中,它同时处理设备树和平台数据。以下是初始化代码,为清晰起见再次编辑:

static const struct of_device_id smc91x_match[] = { { .compatible = “smsc,lan91c94”, }, { .compatible = “smsc,lan91c111”, }, {}, }; MODULE_DEVICE_TABLE(of, smc91x_match); static struct platform_driver smc_driver = {.probe = smc_drv_probe,

 .remove = smc_drv_remove, .driver ={       .name   = "smc91x",       .of_match_table = of_match_ptr(smc91x_match),     },   };   static int __init smc_driver_init(void)   {     return platform_driver_register(&smc_driver);   }   static void __exit smc_driver_exit(void)   {     platform_driver_unregister(&smc_driver);   }   module_init(smc_driver_init);   module_exit(smc_driver_exit);

当驱动程序初始化时,它调用platform_driver_register(),指向struct
platform_driver,其中有一个对探测函数的回调、一个驱动程序名smc91x和一个指向“设备”id的struct的指针。
如果这个驱动程序是由设备树配置的,内核将在设备树节点中的compatible属性和compatible structure元素所指向的字符串之间寻找匹配。对于每个匹配,它调用probe函数。
另一方面,如果它是通过平台数据配置的,则将为指向的字符串上的每个匹配调用probe函数驱动程序名.

probe函数提取有关接口的信息:

static int smc_drv_probe(struct platform_device *pdev) { struct smc91x_platdata *pd = dev_get_platdata(&pdev->dev); const struct of_device_id *match = NULL; struct resource *res, *ires; int irq;

 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);     ires = platform_get_resource(pdev, IORESOURCE_IRQ, 0);     [...]     addr = ioremap(res->start, SMC_IO_EXTENT);     irq = ires->start;[...]

}

对platform_get_resource()的调用从设备树或平台数据中提取内存和irq信息。由驱动程序映射内存并安装中断处理程序。第三个参数在前面的两种情况下都为零,如果有一个以上的特定类型的资源,则会起作用。

设备树允许您配置的不仅仅是基本内存范围和中断。probe函数中有一段代码从设备树中提取可选参数。在此代码段中,它获取register io width属性:

match = of_match_device(of_match_ptr(smc91x_match), &pdev->dev); if (match) { struct device_node *np = pdev->dev.of_node; u32 val; […] of_property_read_u32(np, “reg-io-width”, &val); […]}

对于大多数驱动程序,在Documentation/deviceree/bindings中记录了特定的绑定。对于这个特定的驱动程序,信息在Documentation/deviceree/bindings/net/smsc911x.txt中。
这里要记住的主要一点是,驱动程序应该注册一个探测函数和足够的信息,以便内核调用探测,因为它发现与它所知道的硬件匹配。设备树描述的硬件和设备驱动程序之间的链接是通过compatible属性实现的。平台数据和驱动程序之间的链接是通过名称实现的。

摘要

设备驱动程序的工作是处理设备,通常是物理硬件,但有时是虚拟接口,并以一致和有用的方式将它们呈现给用户空间。Linux设备驱动程序分为三大类:字符、块和网络。在这三种接口中,字符驱动接口是最灵活的,因此也是最常见的。Linux驱动程序适合于一个称为驱动程序模型的框架,该模型通过sysfs公开。在/sys中几乎可以看到设备和驱动程序的整个状态。

每个嵌入式系统都有自己独特的硬件接口和需求集。Linux为大多数标准接口提供了驱动程序,通过选择正确的内核配置,您可以很快得到一个工作的目标板。这就给您留下了非标准组件,您必须添加自己的设备支持。

在某些情况下,您可以通过使用GPIO、I2C等的通用驱动程序来回避这个问题,并编写用户空间代码来完成这项工作。我建议将此作为一个起点,因为它让您有机会在不编写内核代码的情况下熟悉硬件。编写内核驱动程序并不是特别困难,但是如果你真的这么做了,你需要小心编码,以免损害系统的稳定性。

我已经讨论过如何编写内核驱动程序代码:如果你沿着这条路走下去,你将不可避免地想知道如何检查它是否正常工作并检测出任何错误。

嵌入式Linux设备驱动程序:发现硬件配置相关推荐

  1. 嵌入式Linux设备驱动程序:在运行时读取驱动程序状态

    嵌入式Linux设备驱动程序:在运行时读取驱动程序状态 Embedded Linux device drivers: Reading driver state at runtime 在运行时了解驱动程 ...

  2. 嵌入式Linux设备驱动程序:用户空间中的设备驱动程序

    嵌入式Linux设备驱动程序:用户空间中的设备驱动程序 Embedded Linux device drivers: Device drivers in user space Interfacing ...

  3. 嵌入式Linux设备驱动程序:编写内核设备驱动程序

    嵌入式Linux设备驱动程序:编写内核设备驱动程序 Embedded Linux device drivers: Writing a kernel device driver 编写内核设备驱动程序 最 ...

  4. 嵌入式Linux设备驱动程序开发指南14(Linux设备驱动使用DMA)——读书笔记

    Linux设备驱动使用DMA 十四.Linux设备驱动使用DMA 14.1 简介 14.2 缓存一致性 14.3 DMA控制器接口 14.4 流式DMA模块 14.4.1 sdma_sam_m2m.c ...

  5. 嵌入式linux设备驱动程序是,嵌入式Linux设备驱动开发之:按键驱动程序实例-嵌入式系统-与非网...

    11.6  按键驱动程序实例 11.6.1  按键工作原理 LED和蜂鸣器是最简单的GPIO的应用,都不需要任何外部输入或控制.按键同样使用GPIO接口,但按键本身需要外部的输入,即在驱动程序中要处理 ...

  6. 嵌入式Linux设备驱动程序开发指南3(构建Microchip SAMA5D2嵌入式 Linux系统)——读书笔记

    构建Microchip SAMA5D2嵌入式 Linux系统 三.构建Microchip SAMA5D2嵌入式 Linux系统 3.1 获取驱动代码 3.2 配置编译 3.2.1 bootstrap编 ...

  7. 嵌入式linux设备驱动程序是,详解嵌入式Linux设备驱动程序

    随着嵌入式技术的发展,随着嵌入式技术的发展,嵌入式系统将广泛地应用于人 类生活的方方面面.如:基于嵌入式工NTERNET网络的地球电子皮肤,可以嵌入到牙齿 上的手机都在研发之中.著名嵌入式系统专家沈绪 ...

  8. 嵌入式Linux设备驱动程序开发指南20(Linux USB设备驱动)——读书笔记

    Linux USB设备驱动 二十.Linux USB设备驱动 20.1 USB简介 20.1.1 USB2.0总线拓扑 20.1.2 USB总线枚举和设备布局 20.1.3 USB数据传输 20.1. ...

  9. 嵌入式Linux设备驱动程序开发指南18(IIO子系统(二)具有硬件触发功能的IIO子系统ADC模块)——读书笔记

    IIO子系统二 具有硬件触发功能的IIO子系统ADC模块 十八.IIO子系统(二) 具有硬件触发功能的IIO子系统ADC模块 18.1 简介 18.2 设备树 18.3 硬件触发驱动功能分析 18.3 ...

最新文章

  1. shell基础:环境变量
  2. 北京内推 | ​美团无人车团队招聘视觉算法实习生
  3. .Net(C#)用正则表达式清除HTML标签(包括script和style),保留纯本文(UEdit中编写的内容上传到数据库)...
  4. 深入探讨用位掩码代替分支(8):SSE指令集速度测试
  5. CSS Framework 960 Grid System (收)
  6. 服务器最小化安装后的优化脚本
  7. 第512章 河系量子计算机,第512章 河系量子计算机
  8. (2)PCIE简介(学无止境)
  9. apicloud代码压缩和全局加密
  10. 刚刚,无人驾驶公司Roadstar,发公告把联合创始人开除了
  11. CentOS 7.4安装postgresql96
  12. XCode9 拖入文件 不自动添加 compile sources
  13. 360手机助手关于签名校验的分析
  14. gae代码_GAE中的Java EE
  15. github官网进不去解决方案
  16. msm8916 lcd 相关调试点指导
  17. 工作 10 年后,我突然决定读硕士了!
  18. ionic 中的折线图与柱状图
  19. 怎么使用股票委托下单接口?
  20. redis之hkeys、hvals、hgetall的使用

热门文章

  1. 2022-2028年中国在线旅行预订市场投资分析及前景预测报告
  2. mysql64如何配置_win7 64位下如何安装配置mysql-winx64(安装记录)
  3. 【JavaScript总结】JavaScript语法基础:JS高级语法
  4. Eclipse+Maven创建web项目
  5. linux各种模式切换
  6. pytorch JIT浅解析
  7. LeetCode简单题之找出两数组的不同
  8. 全文翻译(一):TVM: An Automated End-to-End Optimizing Compiler for Deep Learning
  9. DeepSpeed超大规模模型训练工具
  10. 自动生成低精度深度学习算子