您的位置:首页 > 运维架构 > Linux

linux 设备驱动 -- Platform

2018-01-11 17:17 351 查看
按照正常理解,先有设备,再需求驱动设备的设备驱动
先看设备如何添加(注册)到内核,下面以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 分配空间,并初始化其中的struct

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;
                    
  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux驱动