小结:
文件的一开始就指出了这个文件的作用:
The core device/driver interactions
在阅读代码之前,建议先看看http://bbs.chinaunix.net/thread-2010492-1-1.html
首先要明确一个概念:一个设备只能对应一个驱动,一个驱动可以挂上很多设备,所以驱动有一个链表,上面挂着支持的设备:
这个文件的代码就是负责实现驱动与设备的关联与释放操作的
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
函数列表:
int device_bind_driver(struct device *dev)
设备与驱动绑定
int driver_probe_done(void)
探测是否有probe正在运行,没有则返回0。
探测的原理是读probe_count变量是否为0,这个变量在静态函数really_probe入口处加1,退出时减1
int driver_probe_device(struct device_driver * drv, struct device * dev)
驱动的绑定,过程如下:
1、 检查dev是否注册,无注册则错误返回
2、 如果match函数存在则调用drv->bus->match(dev, drv),匹配失败则退出
3、 调用really_probe函数进行绑定,这个函数的实现如下:
1、 probe_count加1,用于表示有探测函数正在运行
2、 先将dev->driver = drv,如果出错再取消这个设置
3、 对dev创建link,实现dev和drive文件夹的链接
4、 调用dev->bus->probe或drv->probe进行探测
5、 探测成功则driver_bound(dev)完成绑定,driver_bound的实现如下:
1、 检测dev->knode_driver是否已经设置,设置则说明设备已经关联上驱动,错误返回
2、 klist_add_tail将dev->knode_driver挂到dev->driver->klist_devices链表下,在really_probe中,dev->driver设置为指定驱动,所以这里dev->driver->klist_devices是该驱动中已经关联的设备链表,而dev->knode_driver则是设备的驱动入口,后面应该是根据这个节点来获取dev的结构体。
int device_attach(struct device * dev)
设备与驱动的关联函数
如果dev->driver已关联上驱动,则直接调用device_bind_driver(dev)来创建link及绑定驱动(将dev->knode_driver挂到dev->driver->klist_devices链表下)
如果dev->driver未关联,则调用bus.c中的bus_for_each_drv
int driver_attach(struct device_driver * drv)
同device_attach,区别是遍历的是drv->bus,即查找驱动所在的总线,将总线上的设备尝试关联成drv驱动
而上一个函数则是遍历dev->bus,即查找设备所在的总线,将挂在该总线上的驱动依次和指定设备进行匹配,所以查找完一个就扔一个,因为那个不符合要求
void device_release_driver(struct device * dev)
删除设备对应的驱动,核心操作如下:
//1、删除link文件
//2、将dev->knode_driver从其driver->klist_devices链表中脱出
//3、调用总线或驱动的remove函数
//4、释放设备占用的资源,dev->drivers设置为NULL
void driver_detach(struct device_driver * drv)
释放与指定驱动关联的所有设备
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//根据节点获取设备
#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
struct device_driver {
const char * name;
struct bus_type * bus;
struct kobject kobj; //内嵌的目标
struct klist klist_devices;
struct klist_node knode_bus;
struct module * owner;
const char * mod_name;
struct module_kobject * mkobj;
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);
};
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//驱动与设备的绑定
static void driver_bound(struct device *dev)
{
//设备的knode_driver已经指定了驱动链表,退出
if (klist_node_attached(&dev->knode_driver))
return;
//通过bus通知设备有驱动绑定
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_BOUND_DRIVER, dev);
//将dev->knode_driver驱动链表挂到dev->driver->klist_devices上
//看完下面的really_probe函数的补注:
//在really_probe中,dev->driver设置为指定驱动,所以这里dev->driver->klist_devices是该驱动中已经关联的设备链表,而dev->knode_driver则是设备的驱动入口,后面应该是根据这个节点来获取dev的结构体。
klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//添加驱动关联
static int driver_sysfs_add(struct device *dev)
{
int ret;
//创建链接
ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, kobject_name(&dev->kobj));
if (ret == 0) {
//双向链接
ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
if (ret) //创建失败则删除刚才的链接
sysfs_remove_link(&dev->driver->kobj, kobject_name(&dev->kobj));
}
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//删除驱动关联
static void driver_sysfs_remove(struct device *dev)
{
struct device_driver *drv = dev->driver; //获取设备驱动
if (drv) { //删除驱动关联
sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
sysfs_remove_link(&dev->kobj, "driver");
}
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//设备绑定对应的驱动
int device_bind_driver(struct device *dev)
{
int ret;
ret = driver_sysfs_add(dev); //创建文件链接
if (!ret) driver_bound(dev); //创建成功,驱动绑定
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static atomic_t probe_count = ATOMIC_INIT(0); //原子操作
static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); //等待队列
//返回1则表示成功,返回0表示失败
//操作过程如下:
//1、创建驱动和设备的link文件
//2、调用dev->bus->probe或drv->probe进行探测(总线优先)
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
atomic_inc(&probe_count); //探测计数加1
WARN_ON(!list_empty(&dev->devres_head)); //链表不为空,出警告
dev->driver = drv; //设备的驱动为指定驱动
if (driver_sysfs_add(dev))
goto probe_failed; //添加驱动关联失败
//总线的probe函数存在就调用总线的probe函数,否则调用驱动的probe函数
if (dev->bus->probe)
{
ret = dev->bus->probe(dev);
if (ret) goto probe_failed;
}
else if (drv->probe)
{
ret = drv->probe(dev);
if (ret) goto probe_failed;
}
//探测成功,驱动绑定(设备节点挂到驱动的设备链表中)
driver_bound(dev);
ret = 1;
goto done;
//添加驱动关联失败
probe_failed:
devres_release_all(dev); //设备资源释放
driver_sysfs_remove(dev); //删除驱动关联
dev->driver = NULL; //设备的驱动挂空
ret = 0;
done:
atomic_dec(&probe_count); //探测计数减1(类似put和get)
wake_up(&probe_waitqueue); //唤醒等待队列
return ret; //返回
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//驱动探测是否完成,在really_probe的入口将probe_count加1,退出时减1,所以这个函数用来探测是否有really_probe函数正在运行
int driver_probe_done(void)
{
if (atomic_read(&probe_count))
return -EBUSY;
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//bus.c的driver_bind函数中调用
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
int ret = 0;
//如果设备没有注册,则出错返回
if (!device_is_registered(dev)) return -ENODEV;
//驱动的总线match函数调用失败,退出
if (drv->bus->match && !drv->bus->match(dev, drv))
goto done;
//调用readlly_probe函数实现绑定
ret = really_probe(dev, drv);
done:
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
static int __device_attach(struct device_driver * drv, void * data)
{
struct device * dev = data;
return driver_probe_device(drv, dev);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//在bus.c中,总线探测设备时调用该函数
//设备与驱动的关联,成功返回1
int device_attach(struct device * dev)
{
int ret = 0;
down(&dev->sem);
if (dev->driver) { //设备的驱动已指定(really_probe成功执行)
ret = device_bind_driver(dev); //设备与驱动链表的绑定
if (ret == 0) ret = 1; //成功
else { //失败
dev->driver = NULL;
ret = 0;
}
} else {
//没有为设备绑定驱动,则遍历设备所在的总线,尝试关联驱动,执行__device_attach函数
//bus_for_each_drv在bus.c中
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
}
up(&dev->sem);
return ret;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//驱动和设备的probe
static int __driver_attach(struct device * dev, void * data)
{
struct device_driver * drv = data; //获取驱动
if (dev->parent) down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver) driver_probe_device(drv, dev);
up(&dev->sem);
if (dev->parent) up(&dev->parent->sem);
return 0;
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//遍历驱动所在的总线,对挂在该总线上的设备进行探测
int driver_attach(struct device_driver * drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//从设备中删除驱动,主要步骤如下:
//1、删除link文件
//2、将dev->knode_driver从其driver->klist_devices链表中脱出
//3、调用总线或驱动的remove函数
//4、释放设备占用的资源,dev->drivers设置为NULL
static void __device_release_driver(struct device * dev)
{
struct device_driver * drv;
drv = get_driver(dev->driver); //设备关联的驱动引用加1
if (drv) { //驱动存在
driver_sysfs_remove(dev); //link文件删除
sysfs_remove_link(&dev->kobj, "driver"); //设备与驱动的link删除
klist_remove(&dev->knode_driver); //将设备节点从驱动的dev->driver->klist_devices链表中脱出
if (dev->bus) //发总线通知
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_UNBIND_DRIVER, dev);
//调用总线或者驱动的remove函数
if (dev->bus && dev->bus->remove) dev->bus->remove(dev);
else if (drv->remove) drv->remove(dev);
//释放设备资源
devres_release_all(dev);
dev->driver = NULL; //标记设备没有关联驱动
put_driver(drv); //释放刚要的驱动计数
}
}
//删除设备的驱动,其核心函数就是上面那个
void device_release_driver(struct device * dev)
{
down(&dev->sem);
__device_release_driver(dev);
up(&dev->sem);
}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//释放与指定驱动关联的所有设备(一个驱动可以对应很多设备,这里是释放与这个驱动关联的每一个设备)
void driver_detach(struct device_driver * drv)
{
struct device * dev;
for (;;) {
spin_lock(&drv->klist_devices.k_lock); //驱动的设备链表锁
//驱动对应的与他关联的设备链表为空,退出
if (list_empty(&drv->klist_devices.k_list)) {
spin_unlock(&drv->klist_devices.k_lock);
break;
}
//获取驱动链表中的一个设备
dev = list_entry(drv->klist_devices.k_list.prev,
struct device, knode_driver.n_node);
get_device(dev); //设备引用计数加1,方便操作
spin_unlock(&drv->klist_devices.k_lock);
if (dev->parent) down(&dev->parent->sem);
down(&dev->sem);
if (dev->driver == drv) __device_release_driver(dev); //释放该设备的驱动
up(&dev->sem);
if (dev->parent) up(&dev->parent->sem);
put_device(dev); //释放设备计数
}
}