Platform Devices and Drivers(NET)

来源:互联网 发布:cf手游尼泊尔战龙 数据 编辑:程序博客网 时间:2024/05/17 02:51

翻译来自kernel的platform.txt

See <linux/platform_device.h> for the driver model interface to the platform bus:  platform_device, and platform_driver.  This pseudo-bus is used to connect devices on busses with minimal infrastructure, like those used to integrate peripherals on many system-on-chip processors, or some "legacy" PC interconnects; as opposed to large formally specified ones like PCI or USB. 

      参考linux/platform_device.h中关于driver model to platform bus的信息:platform_device和platform_driver。这个虚拟

总线用来连接在总线上的设备。

Platform devices are devices that typically appear as autonomous entities in the system. This includes legacy port-based devices and host bridges to peripheral buses, and most controllers integrated into system-on-chip platforms.  What they usually have in common is direct addressing from a CPU bus.  Rarely, a platform_device will be connected through a segment of some other kind of bus; but its registers will still be directly addressable.Platform devices are given a name, used in driver binding, and a list of resources such as addresses and IRQs.
      平台设备是系统上的自治实体,这包括传统基于IO口的设备和连接到从设备的主桥,大多数的控制器被整合到片上系统平台。

他们有一个共同点都是CPU总线可寻址的,不常见的是,platform_device将会通过其他类型的总线连接。但是他的寄存器依然

是可寻址的,平台设备被给予一个名字,用来和驱动配对,是一系列资源的集合:地址,中断等等。

struct platform_device { const char*name;u32id;struct devicedev;//dev结构体u32num_resources;struct resource*resource; };
Platform drivers follow the standard driver model convention, where discovery/enumeration is handled outside the drivers, and drivers provide probe() and remove() methods.  They support power management and shutdown notifications using the standard conventions.
     平台驱动遵循标准驱动传统,  发现和枚举在驱动外被处理,驱动提供probe(),remove()方法,他们都支持使用传统方式的

电源管理和关机通知

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 device_driver driver; };
Note that probe() should in general verify that the specified device hardware actually exists; sometimes platform setup code can't be sure.  The probing can use device resources, including clocks, and device platform_data.Platform drivers register themselves the normal way:int platform_driver_register(struct platform_driver *drv);

probe()验证device设备确实存在,有时候platform setup代码都不能确认。probe可以使用device的资源,包括时钟和平台数据

译者:以前看到过一篇驱动的文章,说是probe只要通过,驱动就已经完成百分之80了。

平台驱动注册的方式:

                int platform_driver_register(struct platform_driver *drv);

Or, in common situations where the device is known not to be hot-pluggable, the probe() routine can live in an init section to reduce the driver's runtime memory footprint:int platform_driver_probe(struct platform_driver *drv, int (*probe)(struct platform_device *))Kernel modules can be composed of several platform drivers. The platform core provides helpers to register and unregister an array of drivers:int __platform_register_drivers(struct platform_driver * const *drivers, unsigned int count, struct module *owner); void platform_unregister_drivers(struct platform_driver * const *drivers, unsigned int count);If one of the drivers fails to register, all drivers registered up to that point will be unregistered in reverse order. Note that there is a convenience macro that passes THIS_MODULE as owner parameter:#define platform_register_drivers(drivers, count)

        在一般的场景,这种场景里设备不支持热拔插, probe函数在初始化部分调用来减少驱动程序的内存占用:

        内存模块由多个平台驱动组成,平台核心提供API来注册和注销一组驱动:

       如果一个驱动注册失败,所有的驱动都会按照顺序依次注销,(先入后出)注意:这里有一个方便的宏,这个宏传递THIS MODULE作为自有参数。

Legacy Drivers:  Device Probing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some drivers are not fully converted to the driver model, because they take on a non-driver role:  the driver registers its platform device, rather than leaving that for system infrastructure.  Such drivers can't be hotplugged or coldplugged, since those mechanisms require device creation to be in a different system component than the driver.The only "good" reason for this is to handle older system designs which, like original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware configuration.  Newer systems have largely abandoned that model, in favor of bus-level support for dynamic configuration (PCI, USB), or device tables provided by the boot firmware (e.g. PNPACPI on x86).  There are too many conflicting options about what might be where, and even educated guesses by an operating system will be wrong often enough to make trouble.This style of driver is discouraged.  If you're updating such a driver, please try to move the device enumeration to a more appropriate location, outside the driver.  This will usually be cleanup, since such drivers tend to already have "normal" modes, such as ones using device nodes that were created by PNP or by platform device setup.None the less, there are some APIs to support such legacy drivers.  Avoid using these calls except with such hotplug-deficient drivers.struct platform_device *platform_device_alloc( const char *name, int id);You can use platform_device_alloc() to dynamically allocate a device, which you will then initialize with resources and platform_device_register(). A better solution is usually:struct platform_device *platform_device_register_simple( const char *name, int id,struct resource *res, unsigned int nres);You can use platform_device_register_simple() as a one-step call to allocate and register a device. 

     一些驱动并不能完全转化为driver model,因为他们表现出来的是一个非驱动角色:驱动注册他的平台设备,而不是为系统

机制保留它。这些驱动并不能热拔插或者冷拔插,因为这些机制要求设备的创建在非driver的系统组件里面。

       现在的系统已经放弃以前的model,转而支持总线从而支持动态配置(PCI,USB)或者由固件提供的device tables。

       使用platform_device_alloc()分配一个设备,并这个平台设备初始化,最终调用platform_device_register注册它,当然更

简单的方式是使用platform_device_register_simple,一步到位。

Device Naming and Driver Binding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The platform_device.dev.bus_id is the canonical name for the devices. It's built from two components:    * platform_device.name ... which is also used to for driver matching.    * platform_device.id ... the device instance number, or else "-1" to indicate there's only one.These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and "serial/3" indicates bus_id "serial.3"; both would use the platform_driver named "serial".  While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id) and use the platform_driver called "my_rtc".Driver binding is performed automatically by the driver core, invoking driver probe() after finding a match between device and driver.  If the probe() succeeds, the driver and device are bound as usual.  There are three different ways to find such a match:    - Whenever a device is registered, the drivers for that bus are checked for matches.  Platform devices should be registered very      early during system boot.    - When a driver is registered using platform_driver_register(), all unbound devices on that bus are checked for matches.  Drivers      usually register later during booting, or by module loading.    - Registering a driver using platform_driver_probe() works just like using platform_driver_register(), except that the driver won't      be probed later if another device registers.  (Which is OK, since this interface is only for use with non-hotpluggable devices.) 
          * platform_device.name ... 用来和driver进行匹配

            platform_device.id ... the device instance number, or else "-1" to indicate there's only one.设备实例号,-1表明只有一个该设备


        这些都是连接在一起的,所以name/id "serial/0"表明了bus_id "serial.0",相应的serial/3表明了bus_id“serial.3”,他们都

用相同的名为serial的platform_driver。而my_rtc/-1将是bus_id"my_rtc"没有实例号,使用平台设配驱动“my_rtc”。

        译者:采用platform机制分离driver和device,从而可以用复用,上面大概稍微提到了这一点。

        驱动的匹配是用driver core自动完成,在匹配到device和driver之后会调用driver probe()函数,这里有三种不同的匹配方式:

        device只要被注册,在其总线的上的驱动就会被检查,来匹配它。在系统启动时,平台设备就应该被注册。译者:平台总线也是

一种设备。

        当使用platform_driver_register()注册驱动时,所有的没有配对的设备就会被检查来匹配。驱动一般是在启动之后,或者模块加载时

被注册。

         使用platform_driver_probe进行注册驱动,如果其他的设备注册了,那么驱动将不会被检查。

         

         这里列出来dm9000.c中的相关内容,选自我上一篇文章

          

module_platform_driver(dm9000_driver)    -------->module_driver(dm9000_driver,platform_driver_register,platform_driver_unregister)            ------------>static int __init dm9000_driver_init(void) \                                      { \                                 return platform_driver_register(&dm9000_driver); \                                       } \                                       module_init(dm9000_driver_init); \                        static void __exit dm9000_driver_exit(void) \                                      { \                                      platform_driver_unregister(&dm9000_driver); \                                       } \                                       module_exit(dm9000_driver_exit);  
            然后看看device那边,随便打开一个/arm/mach-s3c24xx/mach-mini2440.c

/* DM9000AEP 10/100 ethernet controller */static struct resource mini2440_dm9k_resource[] = {[0] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE, 4),[1] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE + 4, 4),[2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \| IORESOURCE_IRQ_HIGHEDGE),};//resource资源,具体就是MEM,IRQ宏可以不展开看,因为已经没必要了/* * The DM9000 has no eeprom, and it's MAC address is set by * the bootloader before starting the kernel. */static struct dm9000_plat_data mini2440_dm9k_pdata = {.flags= (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),};//额外数据,但是这里只是有其flagstatic struct platform_device mini2440_device_eth = {.name= "dm9000",.id= -1,//独有.num_resources= ARRAY_SIZE(mini2440_dm9k_resource),//3.resource= mini2440_dm9k_resource,.dev= {.platform_data= &mini2440_dm9k_pdata,},};
       接着看

static struct platform_device *mini2440_devices[] __initdata = {&s3c_device_ohci,&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_rtc,&s3c_device_usbgadget,&mini2440_device_eth,//这就是上面的网卡设备&mini2440_led1,&mini2440_led2,&mini2440_led3,&mini2440_led4,&mini2440_button_device,&s3c_device_nand,&s3c_device_sdi,&s3c2440_device_dma,&s3c_device_iis,&uda1340_codec,&mini2440_audio,};

      再接着

static void __init mini2440_init(void){struct mini2440_features_t features = { 0 };int i;................platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));//这里注册了platform_devicesif (features.count)/* the optional features */platform_add_devices(features.optional, features.count);}

     该函数的调用由

     

MACHINE_START(MINI2440, "MINI2440")/* Maintainer: Michel Pollet <buserror@gmail.com> */.atag_offset= 0x100,.map_io= mini2440_map_io,.init_machine= mini2440_init,.init_irq= s3c2440_init_irq,.init_time= mini2440_init_time,MACHINE_END

#define MACHINE_START(_type,_name)\static const struct machine_desc __mach_desc_##_type\ __used\ __attribute__((__section__(".arch.info.init"))) = {\.nr= MACH_TYPE_##_type,\.name= _name,#define MACHINE_END\};

      在UBOOT篇解析过类似的设计,会由linker来存放一片连续的区域给这个结构体。

      这里提一个问题:

      在什么地方调用了platform_bus_type中的match呢?即match实在什么时候完成的。
      

      答:http://xl028.blog.163.com/blog/static/199730242201231592010799/

              找到了说的很清楚,很详细。目前来说理解到这种程度就可以了。

         

 




0 0
原创粉丝点击