Linux设备模型浅析之驱动篇
本文属本人原创,欢迎转载,转载请注明出处。由于个人的见识和能力有限,不可能面
面俱到,也可能存在谬误,敬请网友指出,本人的邮箱是yzq.seen@gmail.com,博客是
http://zhiqiang0071.cublog.cn。
Linux设备模型,仅仅看理论介绍,比如LDD3的第十四章,会感觉太抽象不易理解,而
通过阅读内核代码就更具体更易理解,所以结合理论介绍和内核代码阅读能够更快速的理解掌
握linux设备模型。这一序列的文章的目的就是在于此,看这些文章之前最好能够仔细阅读
LDD3的第十四章。大部分device和driver都被包含在一个特定bus中,platform_device和
platform_driver就是如此,包含在platform_bus_type中。这里就以对platform_bus_type的调用
为,浅析platform_driver的注过,而理解linux设备模型。platform_bus_type用于
SOC的platformdevice和platformdriver,比如在内核linux-2.6.29中所有S3C2410中的
platformdevice都存在devs.c中。这里就以S3C2410RTC的驱动序rtc-s3c.c为分析
platform_driver_register()的调用过。在文章的最有一对本的devicemodel
,可在阅读本文章的为。阅读这篇文章之前,最好阅读文章Linux设备模型
浅析之设备篇。
一S3C2410RTC的platform_driver定在drivers/rtc/rtc-s3c.c中,代码如
staticstructplatform_drivers3c2410_rtc_driver={
.probe=s3c_rtc_probe,
.remove=__devexit_p(s3c_rtc_remove),
.suspend=s3c_rtc_suspend,
.resume=s3c_rtc_resume,
.driver={
.name="s3c2410-rtc",
.owner=THIS_MODULE,
},
};
由于name="s3c2410-rtc",面会分析到,为一个目的?,
¢/sys/bus/platform/s3c2410-rtc。s3c_rtc_probe()的调用面也会£到,?¥在之前Linux设备
模型浅析之设备篇中?§分析过currency1。''用platform_driver_register()注s3c2410_rtc_driver,
面就分析。
“platform_driver_register()定在drivers/base/platform.c中,代码如
intplatform_driver_register(structplatform_driverdrv)
{
drv->driver.bus=&platform_bus_type;//设?为platform_bus_type
if(drv->probe)
drv->driver.probe=platform_drv_probe;//转存到device_driver中
if(drv->remove)
drv->driver.remove=platform_drv_remove;
if(drv->shutdown)
drv->driver.shutdown=platform_drv_shutdown;
if(drv->suspend)
drv->driver.suspend=platform_drv_suspend;
if(drv->resume)
drv->driver.resume=platform_drv_resume;
returndriver_register(&drv->driver);//?device_driver注到bus,面分析
}
代码中,
1.设?platform_bus_type这个?fifl,为driver和device是通过bus–在一?的,具
体在本中是通过platform_bus_type中注的?调和属·是¥的,在Linux设备模型
浅析之设备篇中£到的driver?device的??就是通过platform_bus_type注的?到
mach()?的。于platform_bus_type的分析请”Linux设备模型浅析之设备篇。面
就分析driver_register()。
?driver_register()定在drivers/base/driver.c中,代码如
intdriver_register(structdevice_driverdrv)
{
intret;
structdevice_driverother;
//…些‰
if((drv->bus->probe&&drv->probe)||
(drv->bus->remove&&drv->remove)||
(drv->bus->shutdown&&drv->shutdown))
printk(KERN_WARNING"Driver''%s''needsupdating-pleaseuse"
"bus_typemethods\n",drv->name);
/通过驱动的??driver,如`到currency1,′明?§注过,???误代码,面会
分析/
other=driver_find(drv->name,drv->bus);
if(other){
put_driver(other);
printk(KERN_ERR"Error:Driver''%s''isalreadyregistered,"
"aborting...\n",drv->name);
return-EEXIST;
}
/driverˉ?到bus的kset,˙¨些文?和?文,面会分析/
ret=bus_add_driver(drv);
if(ret)
returnret;
/?ˉattribute_group,本中?有设?drv->groups/
ret=driver_add_groups(drv,drv->groups);
if(ret)
bus_remove_driver(drv);
returnret;
}
代码中,
1.ˇ如?的—文注所,大部分在bus_add_driver()中?。
bus_add_driver()的用于Linux设备模型浅析之设备篇分析过的
bus_add_device(),不过device?到bus中。面分析driver_find()。
2.driver_find()通过驱动所属bus的driverdrivers_kset?,?定在
drivers/base/driver.c中,代码如
structdevice_driverdriver_find(constcharname,structbus_typebus)
{
structkobjectk=kset_find_obj(bus->p->drivers_kset,name);//在drivers_kset中?
structdriver_privatepriv;
if(k){
priv=to_driver(k);
returnpriv->driver;//??到的driver
}
returnNULL;
}
代码中,
2.1.通过kset_find_obj(bus->p->drivers_kset,name)??driver的kobj,?代码如,
structkobjectkset_find_obj(structksetkset,constcharname)
{
structkobjectk;
structkobjectret=NULL;
spin_lock(&kset->list_lock);
list_for_each_entry(k,&kset->list,entry){//kset->list列kobj
if(kobject_name(k)&&!strcmp(kobject_name(k),name)){//比name??
ret=kobject_get(k);//如`到就ˉa用˙??
break;
}
}
spin_unlock(&kset->list_lock);
returnret;
}
,所有型的driver都注到currency1一个bus->p->drivers_kset->list中,所以可通过???
§注的driver。面分析bus_add_driver()。
3.bus_add_driver()driver注到bus中,在本中是platform_bus_type,?定
在drivers/base/bus.c中,代码如
intbus_add_driver(structdevice_driverdrv)
{
structbus_typebus;
structdriver_privatepriv;
interror=0;
bus=bus_get(drv->bus);//ˉ对bus的a用
if(!bus)
return-EINVAL;
pr_debug("bus:''%s'':adddriver%s\n",bus->name,drv->name);
priv=kzalloc(sizeof(priv),GFP_KERNEL);//这个结体中存??kobj?的o
if(!priv){
error=-ENOMEM;
gotoout_put_bus;
}
klist_init(&priv->klist_devices,NULL,NULL);
priv->driver=drv;//指包含?的drv,以''用
drv->p=priv;//priv存到device_driver
/指bus的drivers_kset,?的用?device_kset?,前是包含所
有注到?bus的driver,是包含所有注到?bus的device。/
priv->kobj.kset=bus->p->drivers_kset;
/?priv->kobj,˙??ˉ到bus->p->drivers_kset中,在本中¨
/sys/bus/platform/drivers/s3c2410-rtc目,面会分析drivers_kset的?
/sys/bus/platform/drivers/目的¨/
error=kobject_init_and_add(&priv->kobj,&driver_ktype,NULL,
"%s",drv->name);
if(error)
gotoout_unregister;
if(drv->bus->p->drivers_autoprobe){//在bus_register()中?§设?为1currency1
error=driver_attach(drv);//所以会???的device,面分析
if(error)
gotoout_unregister;
}
//driver?到klist_drivers,快速?driver
klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);
//driver?ˉ到module模,面会分析
module_add_driver(drv->owner,drv);
/¨/sys//sys/bus/platform/drivers/s3c2410-rtc/uevent属·文,?用?device中的
uevent,可Linux设备模型浅析之设备篇/
error=driver_create_file(drv,&driver_attr_uevent);
if(error){
printk(KERN_ERR"%s:ueventattr(%s)failed\n",
__func__,drv->name);
}
/?ˉbus的?有属·文到/sys//sys/bus/platform/drivers/s3c2410-rtc/目,所有的driver
都?ˉ/
error=driver_add_attrs(bus,drv);
if(error){
/Howthehelldowegetoutofthispickle?Giveup/
printk(KERN_ERR"%s:driver_add_attrs(%s)failed\n",
__func__,drv->name);
}
/”如`??currency1CONFIG_HOTPLUG"“,?¨bind”和"unbind”属·文,可用于?动?
?和?device?driver之的/
error=add_bind_files(drv);
if(error){
/Ditto/
printk(KERN_ERR"%s:add_bind_files(%s)failed\n",
__func__,drv->name);
}
//通过uevent设?个境变量˙通知用户空,以调用序??设?
kobject_uevent(&priv->kobj,KOBJ_ADD);
returnerror;
out_unregister:
kobject_put(&priv->kobj);
out_put_bus:
bus_put(bus);
returnerror;
}
代码中,
3.1.老一点的2.6的内核版本如2.6.10直kobj嵌?在structdevice_driver中,新版的内
核用structdriver_private存?kobj?的o,structdriver_private嵌?在struct
device_driver中。structdriver_private定如
structdriver_private{
structkobjectkobj;//kobj
structklistklist_devices;//用于?到?driver的device
structklist_nodeknode_bus;//用于?到bus->p->klist_drivers
structmodule_kobjectmkobj;//模的kobj,面会£到module
structdevice_driverdriver;//指包含?的driver
}
3.2.''用bus_register()注bus(本是platform_bus_type)的,currency1¨?bus
的ksetsubsys,还¨devices_kset和drivers_kset,都包含在structbus_type_private里
。当也¨他们的目/sys/bus/platform/sys/bus/platform/devices
/sys/bus/platform/drivers。看看structbus_type_private的定
structbus_type_private{
structksetsubsys;//代?bus,里面的kobj是?bus的kobj,也就是最顶层
structksetdrivers_kset;//包含?bus所有的driver
structksetdevices_kset;//包含?bus所有的device
structklistklist_devices;//?用?devices_kset->list用?
structklistklist_drivers;//?用?drivers_kset->list用?
structblocking_notifier_headbus_notifier;//通知bus?的模
unsignedintdrivers_autoprobe:1;//设?是否在driver注的probedevice
structbus_typebus;//?指包含自己的bus
}
?¥?结体的—文注写的?清楚,可到内核的drivers/base/base.h中?看。
3.3.bus_register()定在drivers/base/bus.c中,部分代码如
intbus_register(structbus_typebus)
{
intretval;
structbus_type_privatepriv;
priv=kzalloc(sizeof(structbus_type_private),GFP_KERNEL);
if(!priv)
return-ENOMEM;
priv->bus=bus;//指bus
bus->p=priv;
//bus的?设?为kobj”的?,本中是platform”
retval=kobject_set_name(&priv->subsys.kobj,"%s",bus->name);
if(retval)
gotoout;
priv->subsys.kobj.kset=bus_kset;//指?父kset,bus_kset在buses_init()中?ˉ
priv->subsys.kobj.ktype=&bus_ktype;//设?读属·文的默认法
priv->drivers_autoprobe=1;//设?为注probedevice
/注priv->subsys,?试?,调用currency1kobject_add_internal()注?kobj到
bus_kset父里,˙¨目/sys/bus/platfrom/
retval=kset_register(&priv->subsys);
/¨devices_kset,命为"devices",由于?父kobj是priv->subsys.kobj,所以¨
的目是/sys/bus/platform/devices/
priv->devices_kset=kset_create_and_add("devices",NULL,
&priv->subsys.kobj);
/¨drivers_kset,命为"drivers",由于?父kobj是priv->subsys.kobj,所以¨
的目是/sys/bus/platform/drivers/
priv->drivers_kset=kset_create_and_add("drivers",NULL,
&priv->subsys.kobj);
}
面?分析driver_attach()currency1。
3.4.driver_attach()bus中???的device,?定在drivers/base/dd.c中,代
码如
intdriver_attach(structdevice_driverdrv)
{
/bus的klist_devices列,对每个device''用?调函o__driver_attach()鉴别是否
和driver??/
returnbus_for_each_dev(drv->bus,NULL,drv,__driver_attach);
}
代码中,
3.4.1.bus_for_each_dev()定在在drivers/base/bus.c中,代码如
intbus_for_each_dev(structbus_typebus,structdevicestart,
voiddata,int(fn)(structdevice,void))
{
structklist_iteri;
structdevicedev;
interror=0;
if(!bus)
return-EINVAL;
//设?i
klist_iter_init_node(&bus->p->klist_devices,&i,
(start?&start->knode_bus:NULL));
//''用i
while((dev=next_device(&i))&&!error)
error=fn(dev,data);//''用?调处理
klist_iter_exit(&i);
returnerror;
}
?分析?调__driver_attach()。
3.4.2.?调__driver_attach()定在drivers/base/dd.c中,代码如
staticint__driver_attach(structdevicedev,voiddata)
{
structdevice_driverdrv=data;
/
Lockdeviceandtrytobindtoit.Wedroptheerror
hereandalwaysreturn0,becauseweneedtokeeptrying
tobindtodevicesandsomedriverswillreturnanerror
simplyifitdidn''tsupportthedevice.
driver_probe_device()willspitawarningifthere
isanerror.
/
/调用bus的match(),在这里是platform_bus_type的mach(),¢platform_match()
,?在Linux设备模型浅析之设备篇中分析过/
if(drv->bus->match&&!drv->bus->match(dev,drv))
return0;
if(dev->parent)/NeededforUSB/
down(&dev->parent->sem);
down(&dev->sem);
if(!dev->driver)//本中s3c_device_rtc在注?有到driver,所以这里会执行
driver_probe_device(drv,dev);//这里开probe
up(&dev->sem);
if(dev->parent)
up(&dev->parent->sem);
return0;
}
3.4.2.1.driver_probe_device()在之前的Linux设备模型浅析之设备篇文章?§分析,所
以这里直拷贝过。
driver_probe_device()也是定在drivers/base/dd.c中,代码如
intdriver_probe_device(structdevice_driverdrv,structdevicedev)
{
intret=0;
if(!device_is_registered(dev))//‰dev是否?§注
return-ENODEV;
/调用bus的match(),在这里是platform_bus_type的mach(),¢platform_match()
,?在Linux设备模型浅析之设备篇中分析过/
if(drv->bus->match&&!drv->bus->match(dev,drv))
gotodone;
pr_debug("bus:''%s'':%s:matcheddevice%swithdriver%s\n",
drv->bus->name,__func__,dev_name(dev),drv->name);
//这里真ˇ开调用用户在device_driver中注的probe()
ret=really_probe(dev,drv);
done:
returnret;
}
面分析really_probe(),顾思,?真ˇ开probecurrency1。之前的Linux设备模型浅析之
设备篇文章?§分析,所以这里直拷贝过。
3.4.2.2.really_probe()定在drivers/base/dd.c中,代码如
staticintreally_probe(structdevicedev,structdevice_driverdrv)
{
intret=0;
atomic_inc(&probe_count);
pr_debug("bus:''%s'':%s:probingdriver%swithdevice%s\n",
drv->bus->name,__func__,drv->name,dev_name(dev));
WARN_ON(!list_empty(&dev->devres_head));
dev->driver=drv;//??的driver指到dev,以''用
/如`设备和驱动?§currency1,?在dev目,¢s3c2410-rtc目¨
”为driver"的?文,指?的驱动dev->driver的sys目,˙且在dev->
driver的sys目¨?文,?和dev”的?一样,¢3c2410-wdt",指
/sys/devices/platform/s3c2410-rtc目
/
if(driver_sysfs_add(dev)){
printk(KERN_ERR"%s:driver_sysfs_add(%s)failed\n",
__func__,dev_name(dev));
gotoprobe_failed;
}
//如`设?currency1dev->bus->probe,?调用,在platform_bus_type?有设?
if(dev->bus->probe){
ret=dev->bus->probe(dev);
if(ret)
gotoprobe_failed;
/所以,调用驱动注在device_driver里的probe,这个?常用,用于硬资源,?
硬等,在本中就是调用注到driver的s3c_rtc_probe()。
/
}elseif(drv->probe){
ret=drv->probe(dev);
if(ret)
gotoprobe_failed;
}
//device?ˉ到driver列中,˙通知bus上的设备,明BOUND_DRIVER。
driver_bound(dev);
ret=1;
pr_debug("bus:''%s'':%s:bounddevice%stodriver%s\n",
drv->bus->name,__func__,dev_name(dev),drv->name);
gotodone;
probe_failed:
devres_release_all(dev);
driver_sysfs_remove(dev);
dev->driver=NULL;
if(ret!=-ENODEV&&ret!=-ENXIO){
/drivermatchedbuttheprobefailed/
printk(KERN_WARNING
"%s:probeof%sfailedwitherror%d\n",
drv->name,dev_name(dev),ret);
}
/
Ignoreerrorsreturnedby->probesothatthenextdrivercantry
itsluck.
/
ret=0;
done:
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
returnret;
}
代码中,
3.4.2.2.1.在s3c_rtc_probe()中currency1硬资源和注currency1rtcdevice,所以会产¨?的文
?和文,˙调用rtc_device_register("s3c",&pdev->dev,&s3c_rtcops,THIS_MODULE)注rtc
设备,在Linux设备模型浅析之设备篇中…currency1具体分析,请。
3.5.?执行module_add_driver(),?定在drivers/base/module.c中,代码如
voidmodule_add_driver(structmodulemod,structdevice_driverdrv)
{
chardriver_name;
intno_warn;
structmodule_kobjectmk=NULL;
if(!drv)
return;
if(mod)//本中设?为THIS_MODULE,所以执行
mk=&mod->mkobj;
elseif(drv->mod_name){//如`设?currency1模的?,?到module_kset列中?
structkobjectmkobj;
/Lookupbuilt-inmoduleentryin/sys/modules/
mkobj=kset_find_obj(module_kset,drv->mod_name);//根模?
if(mkobj){
mk=container_of(mkobj,structmodule_kobject,kobj);
/rememberourmodulestructure/
drv->p->mkobj=mk;
/kset_find_objtookareference/
kobject_put(mkobj);
}
}
if(!mk)
return;
/Don''tcheckreturncodes;thesecallsareidempotent/
/本中,假设rtc-s3c.c驱动编译模,?在shell中''用insmod命令ˉ载。所以,
会在/sys/bus/platform/drivers/s3c2410-rtc/目¨为"module"的?文,指
/sys/modules/rtc-s3c目,至于/sys/modules/rtc-s3c目是如何产¨的,稍…分析
/
no_warn=sysfs_create_link(&drv->p->kobj,&mk->kobj,"module");
//本中,¨的driver_name“是platform:s3c2410-rtc”,你看currency1?的¥就会明白
driver_name=make_driver_name(drv);
if(driver_name){
//¨/sys/modules/rtc-s3c/drivers目
module_create_drivers_dir(mk);
/本中,在/sys/modules/rtc-s3c/drivers“目¨为platform:s3c2410-rtc”的
?文,指/sys/bus/platform/drivers/s3c2410-rtc/目/
no_warn=sysfs_create_link(mk->drivers_dir,&drv->p->kobj,
driver_name);
kfree(driver_name);
}
}
代码中,
3.5.1.看currency1上面的分析,一定会产¨一个疑问,/sys/modules/rtc-s3c目是如何产¨的呢?
面就′这个问题。首′′/sys/modules目是如何产¨的。在kernel/params.c中有个?
param_sysfs_init()在–统?的会调用,在?中调用currency1module_kset=
kset_create_and_add("module",&module_uevent_ops,NULL),¨currency1一个kset,产¨
currency1/sys/module目,?kset被赋给currency1全局指module_kset,所以我们所有的驱动模的
mkobj都挂在在的。
3.5.2.再′′/sys/modules/rtc-s3c目是如何产¨的。rtc-s3c.c驱动序被编译模rtc-
s3c.ko。insmodˉ载会产¨–统调用,调用到的内核?口序是定在kernel/module.c中的
init_module()(?¥是sys_init_module())。?会调用在一个文中的load_module()
,?会¨一个structmodule˙根记载的模进行?˙?ˉ?到一个?
中,以以进行a用。在init_module()中会调用到mod_sysfs_init(),?代码如
intmod_sysfs_init(structmodulemod)
{
interr;
structkobjectkobj;
if(!module_sysfs_initialized){
printk(KERN_ERR"%s:modulesysfsnotinitialized\n",
mod->name);
err=-EINVAL;
gotoout;
}
//在module_kset的列中?,看是否?mod?§ˉ载
kobj=kset_find_obj(module_kset,mod->name);
if(kobj){
//ˉ载过currency1?打印?误信息˙??
printk(KERN_ERR"%s:moduleisalreadyloaded\n",mod->name);
kobject_put(kobj);
err=-EINVAL;
gotoout;
}
mod->mkobj.mod=mod;
memset(&mod->mkobj.kobj,0,sizeof(mod->mkobj.kobj));
//kobj.kset指module_kset,也就是包含在的
mod->mkobj.kobj.kset=module_kset;
/为传?的parento为NULL,所以会''用module_kset.kobj为mkobj.kobj的
partentkobj。mod->name就是模,根¨的模,本中模为rtc-
s3c.ko,mod->name=“rtc-s3c”,所以会产¨/sys/module/rtc-s3c目。/
err=kobject_init_and_add(&mod->mkobj.kobj,&module_ktype,NULL,
"%s",mod->name);
if(err)
kobject_put(&mod->mkobj.kobj);
/delayueventuntilfullsysfspopulation/
out:
returnerr;
}
3.5.3.顺′′本中platform_driver_register(&s3c2410_rtc_driver)是被如何调用的,?
被模?s3c_rtc_init(void)调用。module_init(s3c_rtc_init)''?会被赋给
__this_module.init,而?init函o指会在init_module()中被调用。这样
platform_driver_register(&s3c2410_rtc_driver)就被调用currency1,呵呵。
至此,platform_driver_register()?调用。由于platform_devices3c_device_rtc是在
–统?的注的,所以driver能够到??的device,˙产¨一–列的文?和文
,可看附。
个小结,上面的分析可以看出,sys文–统中devicesbusclass和dev目里的内
之的是通过调用device_register()driver_register()和init_module()?的。?
,linux设备模型就这样建立?currency1。
附
注
1.?中黑色?体的椭圆形示是个文?;
2.?中青色?体的椭圆形示是个?文;
3.用箭头示文?之的隶属–和?文?文?之的?–。
|
|