设备驱动模型第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 这个核心函数。
注册设备驱动程序
对设备文件上发出的每个系统调用都由内核转化为相应设备驱动程序的对应函数的调用。为了完成这个操作,设备驱动程序必须注册自己。换句话说,注册一个设备驱动程序意味着把它和它所对应的设备文件连接起来。如果设备文件所对应的驱动程序以前没有注册,则对该设备文件的访问返回错误码 -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 这个核心函数。
相关文章推荐
- (转)platform_driver_register,什么时候调用PROBE函数 注册后如何找到驱动匹配的设备
- platform_driver_register,什么时候调用PROBE函数 注册后如何找到驱动匹配的设备【转】
- platform_driver_register(struct platform_driver *drv)注册后如何找到驱动匹配的设备
- 设备模型、设备与驱动关联的全过程分析 platform_device platform_driver driver bus关系
- platform_driver_register,什么时候调用PROBE函数 注册后如何找到驱动匹配的设备
- platform_driver_register,什么时候调用PROBE函数 注册后如何找到驱动匹配的设备
- 设备模型、设备与驱动关联的全过程分析 platform_device platform_driver driver bus关系
- 平台设备与平台驱动注册过程platform_driver_register与platform_device_register
- platform_driver平台设备驱动模型
- 20150226 IMX257 总线设备驱动模型编程之平台总线设备platform
- linux下设备device_register和驱动driver_register先后注册的影响和关系
- linux设备总线驱动模型 之 platform总线驱动
- [驱动注册]platform_driver_register()与platform_device_register()
- linux内核组件分析之---设备驱动模型之driver
- 总线设备驱动模型:bus->match,driver->probe
- 设备驱动模型之driver
- 从串口驱动的移植看linux2.6内核中的驱动模型 platform device & platform driver【转】
- Linux驱动之设备模型(9)-platform
- [驱动注册]platform_driver_register()与platform_device_register()
- Linux驱动(七)设备模型介绍以及platform设备驱动