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;
先看设备如何添加(注册)到内核,下面以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平台设备驱动架构详解 Linux Platform Device and Driver
- linux设备总线驱动模型 之 platform总线驱动
- Linux-Platform 字符设备驱动
- LINUX设备驱动之platform总线
- Linux平台设备驱动 platform_device
- Linux 设备驱动开发 —— platform设备驱动应用实例解析
- Linux驱动-platform总线设备驱动
- linux设备总线驱动模型 之 platform总线驱动
- linux驱动platform平台设备总线
- Linux驱动(七)设备模型介绍以及platform设备驱动
- linux PlatForm设备驱动
- LINUX设备驱动之platform总线
- Linux 内核--总线设备驱动模型(字符/块/网络设备 && platform设备)
- 【linux设备模型】之platform设备驱动
- 丰富linux驱动内容笔记——platform设备驱动
- Linux驱动设备模型之Platform
- Linux驱动之设备模型(9)-platform
- Linux Platform devices 平台设备驱动
- Linux驱动基础:platform设备驱动
- linux平台设备驱动架构详解 Linux Platform Device and Driver