配色: 字号:
Linux 设备模型驱动篇
2013-01-16 | 阅:  转:  |  分享 
  
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.用箭头示文?之的隶属–和?文?文?之的?–。

献花(0)
+1
(本文系joy_chen首藏)