按照正常理解,先有设备,再需求驱动设备的设备驱动
先看设备如何添加(注册)到内核,下面以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;