zoukankan      html  css  js  c++  java
  • platform_device与platform_driver

          做Linux方面也有三个多月了,对代码中的有些结构一直不是非常明确,比方platform_device与platform_driver一直分不清关系。在网上搜了下,做个总结。两者的工作顺序是先定义platform_device -> 注冊 platform_device->,再定义 platform_driver-> 注冊 platform_driver。

     (1)platform_device设备的注冊过程必须在对应设备驱动载入之前被调用,由于驱动注冊时须要匹配内核中所以已注冊的设备名。platform_device 是在系统启动时在init.c 里的s3c_arch_init() 函数里进行注冊的。这个函数申明为arch_initcall(s3c_arch_init); 会在系统初始化阶段被调用。arch_initcall 的优先级高于module_init,所以会在Platform 驱动注冊之前调用。如今内核中不是採用arch_initcall(s3c_arch_init) 注冊platform_device 结构体而是通过.init_machine成员将其保存在arch_initcall(customize_machine)等待调用(在mach-smdk6410.c中定义的MACHINE_START到MACHINE_END);事实上质是一样的均放在.initcall3.init等待调用。之后再定义结构体struct platform_driver,在驱动初始化函数中调用函数platform_driver_register() 注冊 platform_driver。具体过程描写叙述例如以下:

          Linux从2.6版本号開始引入了platform这个概念,在开发底层驱动程序时,首先要确认的就是设备的资源信息,在2.6内核中将每一个设备的资源用结构platform_device来描写叙述,该结构体定义在kernel/include/linux/platform_device.h中,

    struct platform_device
    
    {
          const char * name;
          u32  id;
          struct device dev;
          u32  num_resources;
          struct resource * resource;
    };
    
    


    该结构一个重要的元素是resource,该元素存入了最为重要的设备资源信息,定义在kernel/include/linux/ioport.h中,
    比方:

    struct resource 
    
    {
           const char *name;
           unsigned long start, end;
           unsigned long flags;
           struct resource *parent, *sibling, *child;
    };
    
    

    实比如:

    static struct resource s3c_usb_resource[] = {
     [0] = {
           .start = S3C_PA_USBHOST,
           .end   = S3C_PA_USBHOST + S3C_SZ_USBHOST - 1,
           .flags = IORESOURCE_MEM,
         },
     [1] = {
           .start = IRQ_UHOST,
           .end   = IRQ_UHOST,
           .flags = IORESOURCE_IRQ,
         }
    };
    
    


    以上是6410的USB  HOST分配的资源信息。第1组描写叙述了这个usb host设备所占用的总线地址范围,起始地址和大小由硬件决定,IORESOURCE_MEM表示第1组描写叙述的是内存类型的资源信息;第2组描写叙述了这个usb host设备的中断号,也由硬件设定,IORESOURCE_IRQ表示第2组描写叙述的是中断资源信息。设备驱动会依据flags来获取对应的资源信息。

          有了resource信息,就能够定义platform_device了:

    struct platform_device s3c_device_usb = {
             .name    = "s3c2410-ohci",  //s3c6410-usb
             .id    = -1,
             .num_resources   = ARRAY_SIZE(s3c_usb_resource),
             .resource   = s3c_usb_resource,
             .dev              = {
                     .dma_mask = &s3c_device_usb_dmamask,
                     .coherent_dma_mask = 0xffffffffUL
                 }
    };
    
    


    有了platform_device就能够调用函数platform_add_devices向系统中加入该设备了。系统中的设备资源都能够採用这样的方式列举在一起,然后成一个指针数组,如:

    static struct platform_device *smdk6410_devices[] __initdata = {

    ......

     &s3c_device_usbgadget,
     &s3c_device_usb,  //jeff add.

    ......

    }

    然后在6410的初始化函数smdk6410_machine_init()中运行:

    platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));将全部的device加入进系统。platform_add_devices的优点在于它是一次性的运行多个platform_device_register。

    (2) 至于驱动程序须要实现结构体struct platform_driver,也定义在kernel/include/linux/platform_device.h中:

    struct platform_driver {
          int (*probe)(struct platform_device *);
          int (*remove)(struct platform_device *);
          void (*shutdown)(struct platform_device *);
          int (*suspend)(struct platform_device *, pm_message_t state);
          int (*suspend_late)(struct platform_device *, pm_message_t state);
          int (*resume_early)(struct platform_device *);
          int (*resume)(struct platform_device *);
          struct pm_ext_ops *pm;
          struct device_driver driver;
    };
    
    


    则该处的USB HOST实现是:

    static struct platform_driver ohci_hcd_s3c2410_driver = {
         .probe  = ohci_hcd_s3c2410_drv_probe,
         .remove  = ohci_hcd_s3c2410_drv_remove,
         .shutdown = usb_hcd_platform_shutdown,
         /*.suspend = ohci_hcd_s3c2410_drv_suspend, */
         /*.resume = ohci_hcd_s3c2410_drv_resume, */
         .driver  = {
              .owner = THIS_MODULE,
              .name = "s3c2410-ohci",
            },
    };
    
    


          在驱动初始化(ohci-hcd.c的1124行)函数中调用函数platform_driver_register()注冊该platform_driver,须要注意的是s3c_device_usb结构中name元素和ohci_hcd_s3c2410_driver 结构中driver.name必须是同样的,这样在platform_driver_register()注冊时会对全部已注冊的platform_device中元素的name和当前注冊的platform_driver的driver.name进行比較,仅仅有找到具备同样名称的platform_device存在后,platform_driver才干注冊成功。当注冊成功时会调用platform_driver结构元素probe函数指针,这里就是ohci_hcd_s3c2410_drv_probe開始探測载入。platform driver中的函数都是以platform device作为參数进入。

    (3)为什么两个name的名字必须匹配才干实现device和driver的绑定?(1)在内核初始化时kernel_init()->do_basic_setup()->driver_init()->platform_bus_init()初始化platform_bus(虚拟总线);(2)设备注冊的时候platform_device_register()->platform_device_add()->(pdev->dev.bus = &platform_bus_type)把设备挂在虚拟的platform bus下;(3)驱动注冊的时候platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev(),对每一个挂在虚拟的platform bus的设备作__driver_attach()->driver_probe_device(),推断drv->bus->match()是否存在而且是否运行成功,此时通过指针运行platform_match,比較strncmp(pdev->name, drv->name, BUS_ID_SIZE),假设相符就调用really_probe(实际就是运行的对应设备的platform_driver->probe(platform_device),注意platform_drv_probe的_dev參数是由bus_for_each_dev的next_device获得)開始真正的探測载入,假设probe成功则绑定该设备到该驱动。

          当进入probe函数后,须要获取设备的资源信息,依据參数type所指定类型,比如IORESOURCE_MEM,来分别获取指定的资源。
    struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);当然,也能够固定资源类型,如获取资源中的中断号:struct int platform_get_irq(struct platform_device *dev, unsigned int num);

          probe函数一般完毕硬件设备使能,struct resource的获取以及虚拟地址的动态映射和详细类型设备的注冊(由于平台设备仅仅是一种虚拟的设备类型);remove函数完毕硬件设备的关闭,struct resource以及虚拟地址的动态映射的释放和详细类型设备的注销。仅仅要和内核本身执行依赖性不大的外围设备 ( 换句话说仅仅要不在内核执行所需的一个最小系统之内的设备 ), 相对独立的拥有各自独自的资源 (addresses and IRQs) ,都能够用platform_driver 实现。如:lcd,usb,uart 等,都能够用platfrom_driver 写,而timer,irq等最小系统之内的设备则最好不用platfrom_driver 机制,实际上内核实现也是这种。


     參考原文:http://blog.chinaunix.net/u1/49507/showart_494193.html

    參考原文:http://blog.csdn.net/yd4330152763132/archive/2010/02/01/5275776.aspx

  • 相关阅读:
    React生命周期, 兄弟组件之间通信
    React组件式编程Demo-用户的增删改查
    React之this.refs, 实现数据双向绑定
    CCF CSP 201812-4 数据中心
    CCF CSP 201812-4 数据中心
    PAT 顶级 1020 Delete At Most Two Characters (35 分)
    PAT 顶级 1020 Delete At Most Two Characters (35 分)
    Codeforces 1245C Constanze's Machine
    Codeforces 1245C Constanze's Machine
    CCF CSP 201712-4 行车路线
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/4095488.html
Copyright © 2011-2022 走看看