您的位置:首页 > 其它

设备驱动模型第2节:platform_driver_register

2014-02-17 15:27 447 查看
第二节 老生常谈 platform_driver_register前世今生
注册设备驱动程序

对设备文件上发出的每个系统调用都由内核转化为相应设备驱动程序的对应函数的调用。为了完成这个操作,设备驱动程序必须注册自己。换句话说,注册一个设备驱动程序意味着把它和它所对应的设备文件连接起来。如果设备文件所对应的驱动程序以前没有注册,则对该设备文件的访问返回错误码 -ENODEV

如果设备驱动程序被静态地编译进内核,则它的注册在内核初始化阶段进行。相反,如果驱动程序作为一个内核模块来编译,则它的注册在模块装入时进行。

一旦设备驱动程序被注册了,它就和设备文件的主设备号连接在一起,而不是和设备文件的路径连接在一起(所以不一定非要把设备挂在/dev/下面,只是为了方便管理)。这样,对设备文件的任何访问都会激活相应的设备驱动程序,而不用管设备文件的路径名称。

下面我们一起来来看看驱动注册的一个流程,看看它会经过哪个点!

/drivers/base/platform.c

int platform_driver_register(struct
platform_driver*drv)//为一个平台级设备注册一个驱动 “struct platform_driver”这个结构体在前面一节有介绍

{

drv->driver.bus =&platform_bus_type;

if (drv->probe)

drv->driver.probe = platform_drv_probe;

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;

return driver_register(&drv->driver);

}



driver_register() --
注册设备驱动程序,搜寻驱动driv对应的设备,并与之关联

/drivers/base/driver.c +222

int driver_register(struct device_driver*
drv)

{

int ret;

struct device_driver *other;

BUG_ON(!drv->bus->p);

/*第一步:[b]检测该驱动是否已经注册到总线上[/b]*/

if ((drv->bus->probe && drv->probe) ||(drv->bus->remove && drv->remove) ||

(drv->bus->shutdown && drv->shutdown))

printk(KERN_WARNING "Driver '%s' needs updating -please use ""bus_type methods\n", drv->name);

other = driver_find(drv->name, drv->bus);//

if (other) {

put_driver(other);

printk(KERN_ERR "Error: Driver '%s' is alreadyregistered, " "aborting...\n", drv->name);

return -EBUSY;

}

/*第二步:[b]总线上没有该驱动把驱动注册到该总线上[/b]*/

ret = bus_add_driver(drv);

if (ret)

return ret;

ret = driver_add_groups(drv, drv->groups);

if (ret)

bus_remove_driver(drv);

return ret;

}



bus_add_driver() -- 将驱动添加到总线上并与总线上的设备匹配

/drivers/base/bus.c+625

int bus_add_driver(struct device_driver*drv)

{

structbus_type *bus;

structdriver_private *priv;

interror = 0;

/*第一步:查找与驱动程序相关的总线*/

bus= bus_get(drv->bus);

if(!bus)

return-EINVAL;

pr_debug("bus:'%s': add driver %s\n", bus->name, drv->name);

/*第二步:把该驱动链到该总线的驱动链表上*/

priv= kzalloc(sizeof(*priv), GFP_KERNEL);

if(!priv) {

error= -ENOMEM;

gotoout_put_bus;

}

klist_init(&priv->klist_devices,NULL, NULL);

priv->driver= drv;

drv->p= priv;

priv->kobj.kset= bus->p->drivers_kset;

error= kobject_init_and_add(&priv->kobj,&driver_ktype, NULL,"%s", drv->name);

if(error)

gotoout_unregister;

/*第三步:寻找该总线上与该驱动相应的设备*/

if(drv->bus->p->drivers_autoprobe) {

error= driver_attach(drv);

if(error)

gotoout_unregister;

}

klist_add_tail(&priv->knode_bus,&bus->p->klist_drivers);

module_add_driver(drv->owner,drv);

/*第四步:创建该驱动在sysfs相应目录下的驱动属性(也就是我们才看见的uevent文件)*/

error= driver_create_file(drv,&driver_attr_uevent);

if(error) {

printk(KERN_ERR"%s: uevent attr (%s) failed\n",__func__, drv->name);

}

error= driver_add_attrs(bus, drv);

if(error) {

/*How the hell do we get out of this pickle? Give up */

printk(KERN_ERR"%s: driver_add_attrs(%s) failed\n",__func__, drv->name);

}

if(!drv->suppress_bind_attrs) {

error= add_bind_files(drv);

if(error) {

/*Ditto */

printk(KERN_ERR"%s: add_bind_files(%s) failed\n",__func__, drv->name);

}

}

kobject_uevent(&priv->kobj,KOBJ_ADD);

return0;

out_unregister:

kobject_put(&priv->kobj);

kfree(drv->p);

drv->p= NULL;

out_put_bus:

bus_put(bus);

returnerror;

}

驱动的注册就跟踪到这,接下去的函数都是很内核级的函数,说白了就是我们工作中几乎接触不到的,那谁会接触,linux内核驱动的维护者。

可见platform_driver_register还是调用了driver_register,也就是所有驱动注册的入口点是driver_register 这个核心函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐