linux 设备驱动 -- Platform

按照正常理解,先有设备,再需求驱动设备的设备驱动
先看设备如何添加(注册)到内核,下面以smdk2410的iic驱动为例

1 platform设备注册
//         File:     arch/arm/mach-s3c2410/mach-smdk2410.c
static struct platform_device *smdk2410_devices[] __initdata = {
    &s3c_device_usb,
    &s3c_device_lcd,
    &s3c_device_wdt,
    &s3c_device_i2c0,
    &s3c_device_iis,
};

static void __init smdk2410_init(void)
{
    s3c_i2c0_set_platdata(NULL);
    platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));  
    smdk_machine_init();
}

//    File:  arch/arm/plat-s3c/dev-i2c0.c
struct platform_device s3c_device_i2c0 = {
    .name          = "s3c2410-i2c",
#ifdef CONFIG_S3C_DEV_I2C1
    .id          = 0,
#else
    .id          = -1,
#endif
    .num_resources      = ARRAY_SIZE(s3c_i2c_resource),
    .resource      = s3c_i2c_resource,
};

2 platform驱动注册

驱动模块入口:
// file:   drivers/i2c/busses/i2c-s3c2410.c

static int __init i2c_adap_s3c_init(void)
{
    return platform_driver_register(&s3c24xx_i2c_driver);
}
subsys_initcall(i2c_adap_s3c_init);  //驱动加载时的入口函数

struct bus_type platform_bus_type = {
     . name        = "platform" ,
     . dev_attrs   = platform_dev_attrs ,
     .match      = platform_match,
     . uevent      = platform_uevent ,
     . pm      = & platform_dev_pm_ops ,
};

相关结构体:
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 (* resume )( struct platform_device *);
    struct platform_device_id *id_table;
     struct device_driver driver ;
        struct device_driver {
             const char        * name ;
             struct bus_type      * bus ;
             struct module        * owner ;
             const char        * mod_name ;    /* used for built-in modules */
             bool suppress_bind_attrs ;     /* disables bind/unbind via sysfs */
             int (* probe ) ( struct device * dev );
             int (* remove ) ( struct device * dev );
             void (* shutdown ) ( struct device * dev );
             int (* suspend ) ( struct device * dev , pm_message_t state );
             int (* resume ) ( struct device * dev );
             const struct attribute_group ** groups ;
             const struct dev_pm_ops * pm ;
             struct driver_private * p ;   //注册到bus时使用: bus_add_driver
                        struct driver_private {
                               struct kobject kobj ;          // kobj.kset = bus->p->drivers_kset  
                               struct klist klist_devices ;   //init
                               struct klist_node knode_bus ;  // 
                               struct module_kobject * mkobj
                               struct device_driver * driver ; // s3c24xx_i2c_driver->driver
                          };
        }   
};

s3c24xx_i2c_driver = {
     . probe       = s3c24xx_i2c_probe ,
     . remove      = s3c24xx_i2c_remove ,
     . id_table    = s3c24xx_driver_ids ,
     . driver      = {
         . owner   = THIS_MODULE ,
         . name    = "s3c-i2c" ,
         . pm  = S3C24XX_DEV_PM_OPS ,
     },
};

3 驱动注册流程
 另外,驱动会找到已经注册到内核的相应的设备

subsys_initcall(i2c_adap_s3c_init);
    platform_driver_register(&s3c24xx_i2c_driver);    
         drv->driver.bus = &platform_bus_type;  //注册到内核platform bus上
         if(s3c24xx_i2c_driver 有 probe/remove/shutdown) 
                s3c24xx_i2c_driver->driver的probe/remove/shutdown  =   platform_drv_probe/platform_drv_remove/platform_drv_shutdown
         driver_register(&s3c24xx_i2c_driver ->driver)  //下面drv=&s3c24xx_i2c_driver ->driver
                if(driver_find(drv->name, drv->bus))
                        abort...          // already registered!! return
         ret = bus_add_driver( drv); 
                给drv ->p 分配空间,并初始化其中的s truct klist klist_devices、driver、kobj
       if (drv->bus->p->drivers_autoprobe) 
            error = driver_attach(drv); //匹配dev和drv
                    //遍历bus的bus->p->klist_devices,对每个device执行 __driver_attach(device, drv)   操作
                    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
                        __driver_attach(device, drv)  :
                           if(drv->bus->match(dev, drv)) //如果匹配成功
                               if (!dev->driver) //dev还没有关联drv
                                  driver_probe_device(drv, dev); //关联
                                     really_probe(dev, drv); //创建/sys目录的链接文件
                                       driver_bound(struct device *dev)
                                         klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);

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 ); //取得s3c24xx_i2c_driver
     /* match against the id table first */
     if ( pdrv -> id_table )//s3c24xx_driver_ids
        //遍历pdrv->id_table数组,找出和pdev->name相等的id,若存在,返回true
         return platform_match_id ( pdrv -> id_table , pdev ) != NULL ;
     /* fall-back to driver name match */
     return ( strcmp ( pdev -> name , drv -> name ) == 0 );
}
                klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
                module_add_driver(drv->owner, drv);

                error = driver_create_file(drv, &driver_attr_uevent);  
                error = driver_add_attrs(bus, drv);
                if (!drv->suppress_bind_attrs) 
                    error = add_bind_files(drv);      
                kobject_uevent(&priv->kobj, KOBJ_ADD);             
        if (ret)
                return ret;
        ret = driver_add_groups( s3c24xx_i2c_driver, s3c24xx_i2c_driver->groups);
        if (ret)
                bus_remove_driver( s3c24xx_i2c_driver);
        return ret;
                    
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值