platform_device和platform_driver

  上班已经3个月了,本来就打算工作中有什么收获就能够写出来的,虽然这段时间里看了很多linux子系统(I2C,TTY,SPI,MTD,网络,USB)相关的内容,但是,因为没有做过比较多的实践经验,所以不敢马上写出来,但是又怕过了段时间很多东西都忘了,所以还是先把这段时间的感悟和心得写下来。如果要开始写linux系统的话,我觉得就不得不从platform_device和platform_driver开始,因为在一家芯片公司做的是SoC,片上的很多硬件控制器在linux中抽象成platform_device,全部都挂载在一条虚拟的platform bus上.

platform描述的资源有一个共同点可以在cpu上直接取址。

在linux内核中,匹配函数默认使用bus注册的匹配函数,如果bus没有注册则使用driver注册的匹配函数。

在系统每注册一个驱动的时候,会寻找一个与之匹配的设备,而匹配由总线完成。

对platform_dev0ce定义通常在BSP的板文件中实现,在板文件中,将platform_device归纳为一个数组,最终通过platform_add_device()函数统一注册。

所谓注册就是driver中的内核成员对象kobject的链表(kobject->entry)加入到bus总线中的bus->type->kset->list链表中。

每次系统增加一个platform_driver,platform_bus_type都会启动scan过程,让新加入的driver扫描整个platform_bus上的device链表,遍历整个platform_bus上的driver链表看是否有合适的该device的driver。

  编写硬件控制器驱动的时候,如果是platform_device,就应该在module_init(xxx_init)里面的函数.调用platform_driver_probe(&xxx_platform_driver,xxx_probe);这个函数只能够注册非热插拔设备的驱动。函数里最后还是调用platform_driver_register().

   /**
   * platform_driver_register - register a driver for platform-level devices
   * @drv: platform driver structure
   */
  int platform_driver_register(struct platform_driver *drv)
  {
          drv->driver.bus = &platform_bus_type;
          if (drv->probe)
                  drv->driver.probe = platform_drv_probe;
          if (drv->remove)
                  drv->driver.remove = platform_drv_remove;
          if (drv->shutdown)
                  drv->driver.shutdown = platform_drv_shutdown;
  
          return driver_register(&drv->driver);
  }
  EXPORT_SYMBOL_GPL(platform_driver_register);

其中platform_bus_type:

  struct bus_type platform_bus_type = {
          .name           = "platform",
          .dev_attrs      = platform_dev_attrs,
          .match          = platform_match,
          .uevent         = platform_uevent,
          .pm             = &platform_dev_pm_ops,
  };
  EXPORT_SYMBOL_GPL(platform_bus_type);
其中比较重要的是platform_match:

  /**
   * platform_match - bind platform device to platform driver.
   * @dev: device.
   * @drv: driver.
   *
   * Platform device IDs are assumed to be encoded like this:
   * "<name><instance>", where <name> is a short description of the type of
   * device, like "pci" or "floppy", and <instance> is the enumerated
   * instance of the device, like '0' or '42'.  Driver IDs are simply
   * "<name>".  So, extract the <name> from the platform_device structure,
   * and compare it against the name of the driver. Return whether they match
   * or not.
   */
  static int platform_match(struct device *dev, struct device_driver *drv)
  {
          struct platform_device *pdev = to_platform_device(dev);
          struct platform_driver *pdrv = to_platform_driver(drv);
  
          /* Attempt an OF style match first */
          if (of_driver_match_device(dev, drv))
                  return 1;
  
          /* Then try to match against the id table */
          if (pdrv->id_table)
                  return platform_match_id(pdrv->id_table, pdev) != NULL;
  
          /* fall-back to driver name match */
          return (strcmp(pdev->name, drv->name) == 0);
  }
可以看出来platform_driver和platform_device匹配有三种方法,一般来说,都采用最后看driver和device的名字是否相同,如果在arch/xxx_chips/xxx_system/下的platform.c中有已经写好的platform_device(里面包含了中断,物理地址等resource),最终调用platform_add_device().添加到内核中。

如果platform_device和platform_driver的name相同的话,最后调用xxx_probe()函数,里面就是对物理设备控制器的初始化和驱动注册函数(xxx_regsisterx)。


内存映射方式:外设的I/O端口的物理地址被映射到内存地址空间中,使I/O端口成为内存的一部分,CPU可以像访问一个内存单元那样访问I/O端口,而不需要设立专门的外设I/O指令。

一般来说,在系统运行时,外设的I/O内存资源,物理地址都是已知的,由硬件设计决定。

ioremap()用来将I/O资源的物理地址映射到核心虚拟空间。

申请I/O端口:request_region();

申请I/O内存:request_mem_region();没有做实际的映射工作,高速内核要使用一块内存地址声明占有。

内核中有两棵树,一棵是iomem_resource,另一棵时ioport_resource,分别代表着不同性质的地址资源。

   struct resource ioport_resource = {
           .name   = "PCI IO",
           .start  = 0,
           .end    = IO_SPACE_LIMIT,
           .flags  = IORESOURCE_IO,
   };
   EXPORT_SYMBOL(ioport_resource);
   
   struct resource iomem_resource = {
           .name   = "PCI mem",
           .start  = 0,
           .end    = -1,
           .flags  = IORESOURCE_MEM,
   };
   EXPORT_SYMBOL(iomem_resource);



你可能感兴趣的:(platform_device和platform_driver)