本章重点讲解思想、思想、思想。

12.1 linux驱动的软件架构

  下述三种思想,在linux的spi、iic、usb等复杂驱动里广泛使用。后面几节分别对这些思想进行详细说明。

  • 思想1:驱动与设备分离,linux采用总线、设备和驱动模型,驱动只管驱动,设备只管设备,总线负责匹配设备和驱动;驱动从标准途径拿到板级信息(设备信息,现在都已dts的形式存在),这样驱动就可以放之四海而皆准了,结构如下图。

   说到“总线”,有很多种,如I2C、SPI等,linux还为没有硬件总线的设备提出一种虚拟总线,即platform总线,同时还有对应的platform设备和platform驱动。

  

  为啥? linux驱动要支持很多硬件,如果把设备信息写到驱动里,驱动会有非常多分支,一堆东西揉到一起,换成一锅粥,所以要把设备和驱动分开。

  • 思想2:分层设计思想,file_opretations、IO模型等,是很多驱动共有的部分,linux提炼出一个中间层,把这些部分封装起来,供所有驱动使用。这就引出了软件分层的思想。

  • 思想3:主机与外设分隔的思想。例如spi分为主机和外设,不同CPU有M种spi主机,同时不通外设也有N种,如果直接交叉支持,势必有M*N种组合,代码会非常复杂。需要在主机和外设中间插入一个标准API,把M和N分隔开,主机和外设都使用标准API与中间的分隔层接口,这样只需要实现M个主机和N个外设驱动即可,这种思想也叫“高内聚,低耦合”

     

12.2 platform设备驱动

12.2.1  platform总线、设备与驱动

  • linux 2.6以后,采用总线、设备、驱动模型;
  • platform的引入:有些设备本身依附一种总线,例如IIC、SPI、PCI、SPI等,很容易实现linux的总线/设备/驱动模型;但有些设备不依赖总线,例如SOC系统内部集成的独立外设控制器等,基于这种情况,linux发明了一种虚拟总线,即platform总线,对应的设备和驱动分别为platform_device和platform_driver。
  • platform device不是针对linux的字符设备、块设备、网络设备的,是linux的一种附加手段。SOC内部集成的各控制器,例如IIC、RTC、LCD等一般都归纳为platform device。
  • platform作为一种虚拟总线,与其他实体总线地位对等,例如SPI/IIC总线等,掌握了platform总线,其他总线也是类似的。

  关键数据结构:

  1. device

  1. #include <linux/platform_device.h>
  2.  
  3. struct platform_device {
  4. const char *name;
  5. int id;
  6. bool id_auto;
  7. struct device dev;          // linux/device.h里定义,总线match时,实际match的是dev,所有设备共性的部分
  8. u32 num_resources;        // 资源
  9. struct resource *resource;
  10.  
  11. const struct platform_device_id *id_entry;
  12.  
  13. /* MFD cell pointer */
  14. struct mfd_cell *mfd_cell;
  15.  
  16. /* arch specific additions */
  17. struct pdev_archdata archdata;
  18. };

2.driver

  1. #include <linux/platform_device.h>

  2. // probe等函数由内核的platform机制实现了,驱动需要填充driver结构体
  3. struct platform_driver {
  4. int (*probe)(struct platform_device *);
  5. int (*remove)(struct platform_device *);
  6. void (*shutdown)(struct platform_device *);
  7. int (*suspend)(struct platform_device *, pm_message_t state);  // 电源管理,基本不用了,有driver里的
  8. int (*resume)(struct platform_device *);              // 同上
  9. struct device_driver driver;                     // 所有驱动共享的部分,match以后driver.probe执行,同时调用外层platform_driver的prove执行               
  10. const struct platform_device_id *id_table;             // 一组ID表
  11. bool prevent_deferred_probe;
  12. };
  13.  
  14. // linux/device.h
  15. /**
  16. * struct device_driver - The basic device driver structure
  17. * @name: Name of the device driver.
  18. * @bus: The bus which the device of this driver belongs to.
  19. * @owner: The module owner.
  20. * @mod_name: Used for built-in modules.
  21. * @suppress_bind_attrs: Disables bind/unbind via sysfs.
  22. * @of_match_table: The open firmware table.
  23. * @acpi_match_table: The ACPI match table.
  24. * @probe: Called to query the existence of a specific device,
  25. * whether this driver can work with it, and bind the driver
  26. * to a specific device.
  27. * @remove: Called when the device is removed from the system to
  28. * unbind a device from this driver.
  29. * @shutdown: Called at shut-down time to quiesce the device.
  30. * @suspend: Called to put the device to sleep mode. Usually to a
  31. * low power state.
  32. * @resume: Called to bring a device from sleep mode.
  33. * @groups: Default attributes that get created by the driver core
  34. * automatically.
  35. * @pm: Power management operations of the device which matched
  36. * this driver.
  37. * @p: Driver core's private data, no one other than the driver
  38. * core can touch this.
  39. *
  40. * The device driver-model tracks all of the drivers known to the system.
  41. * The main reason for this tracking is to enable the driver core to match
  42. * up drivers with new devices. Once drivers are known objects within the
  43. * system, however, a number of other things become possible. Device drivers
  44. * can export information and configuration variables that are independent
  45. * of any specific device.
  46. */
  47. struct device_driver {
  48. const char *name;
  49. struct bus_type *bus;              // 对应总线结构体指针
  50. struct module *owner;
  51. const char *mod_name; /* used for built-in modules */
  52.  
  53. bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
  54.  
  55. const struct of_device_id *of_match_table;
  56. const struct acpi_device_id *acpi_match_table;
  57.  
  58. int (*probe) (struct device *dev);      // 总线match完设备和驱动以后,这个函数会执行,
                    // 形参dev就是被match的设备信息!!!
  59. int (*remove) (struct device *dev);
  60. void (*shutdown) (struct device *dev);
  61. int (*suspend) (struct device *dev, pm_message_t state);
  62. int (*resume) (struct device *dev);
  63. const struct attribute_group **groups;
  64.  
  65. const struct dev_pm_ops *pm;
  66.  
  67. struct driver_private *p;
  68. };

3.总线

总线的类型为bus_type,内核直接为platform定义了一个总线实体

  1. // drivers/base/platform.c,这些函数都是现成的,在platform机制里实现了。
  2. struct bus_type platform_bus_type = {
  3. .name = "platform",
  4. .dev_groups = platform_dev_groups,
  5. .match = platform_match,      // 匹配函数,关键
  6. .uevent = platform_uevent,
  7. .pm = &platform_dev_pm_ops,
  8. };
  9.  
  10. /**
  11. * platform_match - bind platform device to platform driver.
  12. * @dev: device.
  13. * @drv: driver.
  14. *
  15. * Platform device IDs are assumed to be encoded like this:
  16. * "<name><instance>", where <name> is a short description of the type of
  17. * device, like "pci" or "floppy", and <instance> is the enumerated
  18. * instance of the device, like '0' or '42'. Driver IDs are simply
  19. * "<name>". So, extract the <name> from the platform_device structure,
  20. * and compare it against the name of the driver. Return whether they match
  21. * or not.
  22. */
  23. static int platform_match(struct device *dev, struct device_driver *drv)
  24. {
  25. struct platform_device *pdev = to_platform_device(dev);
  26. struct platform_driver *pdrv = to_platform_driver(drv);
  27.  
  28. /* Attempt an OF style match first */  // 基于dts匹配优先级最高
  29. if (of_driver_match_device(dev, drv))
  30. return ;
  31.  
  32. /* Then try ACPI style match */  
  33. if (acpi_driver_match_device(dev, drv))
  34. return ;
  35.  
  36. /* Then try to match against the id table */    // 基于platform device和platform driver的ID
  37. if (pdrv->id_table)
  38. return platform_match_id(pdrv->id_table, pdev) != NULL;
  39.  
  40. /* fall-back to driver name match */    // 基于名字
  41. return (strcmp(pdev->name, drv->name) == );
  42. }

  linux 2.6以及之前版本,platform device通常定义在板级bsp里,然后再add;而3.x以后,改为自动展开dts,形成若干device。

12.2.2 将globalmem作为platform设备

没法实验,只罗列代码。

  1. static int globalfifo_probe(struct platform_device *pdev)    // 完成原来globalmem_init的任务
  2. {
  3. int ret;
  4. dev_t devno = MKDEV(globalfifo_major, );
  5.  
  6. if (globalfifo_major)
  7. ret = register_chrdev_region(devno, , "globalfifo");
  8. else {
  9. ret = alloc_chrdev_region(&devno, , , "globalfifo");
  10. globalfifo_major = MAJOR(devno);
  11. }
  12. if (ret < )
  13. return ret;
  14.  
  15. globalfifo_devp = devm_kzalloc(&pdev->dev, sizeof(*globalfifo_devp),GFP_KERNEL);
  16. if (!globalfifo_devp) {
  17. ret = -ENOMEM;
  18. goto fail_malloc;
  19. }
  20.  
  21. globalfifo_setup_cdev(globalfifo_devp, );
  22.  
  23. mutex_init(&globalfifo_devp->mutex);
  24. init_waitqueue_head(&globalfifo_devp->r_wait);
  25. init_waitqueue_head(&globalfifo_devp->w_wait);
  26.  
  27. return ;
  28.  
  29. fail_malloc:
  30. unregister_chrdev_region(devno, );
  31. return ret;
  32. }
  33.  
  34. static int globalfifo_remove(struct platform_device *pdev)    // 完成原来globalmem_exit的任务
  35. {
  36. cdev_del(&globalfifo_devp->cdev);
  37. unregister_chrdev_region(MKDEV(globalfifo_major, ), );
  38.  
  39. return ;
  40. }
  41.  
  42. static struct platform_driver globalfifo_driver = {
  43. .driver = {
  44. .name = "globalfifo",
  45. .owner = THIS_MODULE,
  46. },
  47. .probe = globalfifo_probe,
  48. .remove = globalfifo_remove,
  49. };
  50.  
  51. module_platform_driver(globalfifo_driver);    // !!!注册platform驱动,/sys/bus/platform/drivers/globalmem,多出一个globalmem子目录

  52. // 在板级bsp里(arch/arm/mach-xxx/mach-yyy.c,xxx为SOC名,yyy为board名)增加platform device,
    // 系统初始化时添加到系统里,/sys/device/platform/globalmem,多出一个globalmem子目录,该目录中有driver符号链接,
    // 指向/sys/bus/platform/drivers/globalmem
  53. static struct platform_device globalfifo_device = {
  54. .name = "globalfifo",
  55. .id = -,
  56. };

12.2.3 platform设备资源和数据

在platform_device结构体中,有resource结构体,表示该device的资源,start和end随flag的变化而表示不同的含义:

flag:

    1. IORESOURCE_MEMstartend表示platform device占据的开始开始地址和结束地址
  • IORESOURCE_IRQ,start和end表示使用中断号的开始值和结束值,如果只有1个中断号,则开始值和结束值相同

resource在板级支持包或者dts里定义,dts的定义后续说明,板级支持包都淘汰了,不再说明。

   /* Resources are tree-like, allowing

  1. * nesting etc..
  2. */
  3. struct resource {
  4. resource_size_t start;
  5. resource_size_t end;
  6. const char *name;
  7. unsigned long flags;
  8. struct resource *parent, *sibling, *child;
  9. };
  10.  
  11. /*
  12. * IO resources have these defined flags.
  13. */
  14. #define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
  15.  
  16. #define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */
  17. #define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */
  18. #define IORESOURCE_MEM 0x00000200
  19. #define IORESOURCE_REG 0x00000300 /* Register offsets */
  20. #define IORESOURCE_IRQ 0x00000400
  21. #define IORESOURCE_DMA 0x00000800
  22. #define IORESOURCE_BUS 0x00001000
  23.  
  24. #define IORESOURCE_PREFETCH 0x00002000 /* No side effects */
  25. #define IORESOURCE_READONLY 0x00004000
  26. #define IORESOURCE_CACHEABLE 0x00008000
  27. #define IORESOURCE_RANGELENGTH 0x00010000
  28. #define IORESOURCE_SHADOWABLE 0x00020000
  29.  
  30. #define IORESOURCE_SIZEALIGN 0x00040000 /* size indicates alignment */
  31. #define IORESOURCE_STARTALIGN 0x00080000 /* start field is alignment */
  32.  
  33. #define IORESOURCE_MEM_64 0x00100000
  34. #define IORESOURCE_WINDOW 0x00200000 /* forwarded by bridge */
  35. #define IORESOURCE_MUXED 0x00400000 /* Resource is software muxed */
  36.  
  37. #define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
  38. #define IORESOURCE_DISABLED 0x10000000
  39. #define IORESOURCE_UNSET 0x20000000
  40. #define IORESOURCE_AUTO 0x40000000
  41. #define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */
  42.  
  43. /* PnP IRQ specific bits (IORESOURCE_BITS) */
  44. #define IORESOURCE_IRQ_HIGHEDGE (1<<0)
  45. #define IORESOURCE_IRQ_LOWEDGE (1<<1)
  46. #define IORESOURCE_IRQ_HIGHLEVEL (1<<2)
  47. #define IORESOURCE_IRQ_LOWLEVEL (1<<3)
  48. #define IORESOURCE_IRQ_SHAREABLE (1<<4)
  49. #define IORESOURCE_IRQ_OPTIONAL (1<<5)
  50.  
  51. /* PnP DMA specific bits (IORESOURCE_BITS) */
  52. #define IORESOURCE_DMA_TYPE_MASK (3<<0)
  53. #define IORESOURCE_DMA_8BIT (0<<0)
  54. #define IORESOURCE_DMA_8AND16BIT (1<<0)
  55. #define IORESOURCE_DMA_16BIT (2<<0)
  56.  
  57. #define IORESOURCE_DMA_MASTER (1<<2)
  58. #define IORESOURCE_DMA_BYTE (1<<3)
  59. #define IORESOURCE_DMA_WORD (1<<4)
  60.  
  61. #define IORESOURCE_DMA_SPEED_MASK (3<<6)
  62. #define IORESOURCE_DMA_COMPATIBLE (0<<6)
  63. #define IORESOURCE_DMA_TYPEA (1<<6)
  64. #define IORESOURCE_DMA_TYPEB (2<<6)
  65. #define IORESOURCE_DMA_TYPEF (3<<6)
  66.  
  67. /* PnP memory I/O specific bits (IORESOURCE_BITS) */
  68. #define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */
  69. #define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */
  70. #define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */
  71. #define IORESOURCE_MEM_TYPE_MASK (3<<3)
  72. #define IORESOURCE_MEM_8BIT (0<<3)
  73. #define IORESOURCE_MEM_16BIT (1<<3)
  74. #define IORESOURCE_MEM_8AND16BIT (2<<3)
  75. #define IORESOURCE_MEM_32BIT (3<<3)
  76. #define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */
  77. #define IORESOURCE_MEM_EXPANSIONROM (1<<6)
  78.  
  79. /* PnP I/O specific bits (IORESOURCE_BITS) */
  80. #define IORESOURCE_IO_16BIT_ADDR (1<<0)
  81. #define IORESOURCE_IO_FIXED (1<<1)
  82.  
  83. /* PCI ROM control bits (IORESOURCE_BITS) */
  84. #define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */
  85. #define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */
  86. #define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */
  87. #define IORESOURCE_ROM_BIOS_COPY (1<<3) /* ROM is BIOS copy, resource field overlaid */
  88.  
  89. /* PCI control bits. Shares IORESOURCE_BITS with above PCI ROM. */
  90. #define IORESOURCE_PCI_FIXED (1<<4) /* Do not move resource */

12.3 设备驱动的分层思想

稍后具体分析1个linux的驱动比较好。

12.4 主机驱动与外设驱动分离的设计思想

核心是定义好外设与主机之间的标准API,两边都使用标准API。具体分析一个驱动,便于理解。

12.5 总结

掌握思想,用这些思想去分析具体驱动,多读读驱动,慢慢就能理解这些思想了。

《linux设备驱动开发详解》笔记——12linux设备驱动的软件架构思想的更多相关文章

  1. linux设备驱动开发详解 笔记

      在目录的 Makefile 中关于 RTC_DRV_S3C 的编译脚本为: obj -$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o 上述脚本意味着如果 RTC_DRV_S3 ...

  2. Linux设备驱动开发详解

    Linux设备驱动开发详解 http://download.csdn.net/detail/wuyouzi067/9581380

  3. 嵌入式Linux应用程序开发详解------(创建守护进程)

    嵌入式Linux应用程序开发详解 华清远见 本文只是阅读文摘. 创建一个守护进程的步骤: 1.创建一个子进程,然后退出父进程: 2.在子进程中使用创建新会话---setsid(): 3.改变当前工作目 ...

  4. 《linux设备驱动开发详解》笔记——14 linux网络设备驱动

    14.1 网络设备驱动结构 网络协议接口层:硬件无关,标准收发函数dev_queue_xmit()和netif_rx();  注意,netif_rx是将接收到的数据给上层,有时也在驱动收到数据以后调用 ...

  5. 《linux设备驱动开发详解》笔记——6字符设备驱动

    6.1 字符设备驱动结构 先看看字符设备驱动的架构: 6.1.1 cdev cdev结构体是字符设备的核心数据结构,用于描述一个字符设备,cdev定义如下: #include <linux/cd ...

  6. 《Linux设备驱动开发详解(第2版)》配套视频登录51cto教育频道

    http://edu.51cto.com/course/course_id-379-page-1.html http://edu.51cto.com/course/course_id-379-page ...

  7. Linux设备驱动开发详解-Note(11)--- Linux 文件系统与设备文件系统(3)

    Linux 文件系统与设备文件系统(3) 成于坚持,败于止步 sysfs 文件系统与 Linux 设备模型 1.sysfs 文件系统 Linux 2.6 内核引入了 sysfs 文件系统,sysfs ...

  8. (转)FS_S5PC100平台上Linux Camera驱动开发详解(一) .

     平台linuxstructlinux内核videocam 说明:        理解摄像头驱动需要四个前提:        1)摄像头基本的工作原理和S5PC100集成的Camera控制器的工作原理 ...

  9. (转)FS_S5PC100平台上Linux Camera驱动开发详解(二)

    4-3 摄像头的初始化流程及v4l2子设备驱动 这个问题弄清楚了以后下面就来看获得Camera信息以后如何做后续的处理: 在fimc_init_global调用结束之后我们获得了OV9650的信息,之 ...

随机推荐

  1. .NET Core模块化

    .NET Core模块化 源码地址 GitHub:https://github.com/iamoldli/NetModular 演示地址 地址:https://nm.iamoldli.com账户:ad ...

  2. block size大小

    1.用tune2fs查看block size大小: 1 2 tune2fs -l /dev/sda1 |grep "Block size" Block size: 1024 2.用 ...

  3. Smarty中的请求变量和保留变量的使用范例

    PHP中提供的超全局数组 Smarty中对应的请求变量 $_GET               <{$smarty.get}> $_POST                         ...

  4. 30个提高Web程序执行效率的好经验

    尽量避免使用DOM.当需要反复使用DOM时,先把对DOM的引用存到JavaScript本地变量里再使用.使用设置innerHTML的方法来替换document.createElement/append ...

  5. [转]兼容各个浏览器的H.264播放: H.264+HTML5+FLOWPLAYER+WOWZA+RMTP

    一.方案确定 计划做视频播放,要求能够播放H264编码的mp4文件,各个浏览器,各种终端都能播放. 首先查找可行性方案, http://www.cnblogs.com/sink_cup/archive ...

  6. nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点

    nodejs 实践:express 最佳实践(八) egg.js 框架的优缺点 优点 所有的 web开发的点都考虑到了 agent 很有特色 文件夹规划到位 扩展能力优秀 缺点 最大的问题在于: 使用 ...

  7. UI2_同步下载

    // // ViewController.m // UI2_同步下载 // // Created by zhangxueming on 15/7/17. // Copyright (c) 2015年 ...

  8. Fleet(集群管理器)

    工作原理 fleet 是通过systemd来控制你的集群的,控制的任务被称之为unit(单元),控制的命令是fleetctl unit运行方式 unit的运行方式有两种: standard globa ...

  9. ABAP接口用法

    1.定义接口INTERFACE intf [PUBLIC].   [components] ENDINTERFACE. 2.注意点: 2.1.接口中所定义的所有东西默认都是公共的,所以不用也不能写PU ...

  10. Ubuntu 配置IP地址方法

    接到一客户的服务器,开机已启动发现是Ubuntu系统,当时有点郁闷了,心想没有配置过ubuntu系统,这客户还在旁边了,心里有点紧张了,于是开始上网寻找各种方法配置,最终将IP配置好,给客户上架调试通 ...