驱动中remove和shutdown根本的区别在于调用的时机不同,我们以platform驱动为例,如下:
static struct platform_driver s3cmci_driver = {
.driver = {},
.remove = __devexit_p(s3cmci_remove),
.shutdown = s3cmci_shutdown,
};
static int __init s3cmci_init(void)
{
return platform_driver_register(&s3cmci_driver);
}
int platform_driver_register(struct platform_driver *drv)
{
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
return driver_register(&drv->driver);
}
14、15行,drv->remove是一个特定(具体)platform驱动的remove回调,比如这里的s3cmci_remove函数。drv->driver.remove是platform框架提供的,所有platform驱动通用。那么,一个特定驱动的remove函数如何得到调用?答案在platform_drv_remove函数中:
static int platform_drv_remove(struct device *_dev)
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
return drv->remove(dev);
}
platform_drv_remove相当于一个桥梁,实际干事的还是s3cmci_remove函数。16、17行的shutdown同理。至此,我们知道往后只需关注drv->driver.remove和drv->driver.shutdown就可以了。
remove/shutdown回调时机:
(1)卸载驱动的时候,remove调用
(2)设备移除的时候,与设备关联的驱动需要移除,remove调用
(3)系统关机/重启的时候,shutdown调用
驱动卸载:
void platform_driver_unregister(struct platform_driver *drv)
-->driver_unregister(&drv->driver)
---->bus_remove_driver(drv)
------>driver_detach(drv)
{
struct device_private *dev_prv;
struct device *dev;
for (;;) {
spin_lock(&drv->p->klist_devices.k_lock);
if (list_empty(&drv->p->klist_devices.k_list)) {
spin_unlock(&drv->p->klist_devices.k_lock);
break;
}
dev_prv = list_entry(drv->p->klist_devices.k_list.prev,
struct device_private,
knode_driver.n_node);
dev = dev_prv->device;
get_device(dev);
spin_unlock(&drv->p->klist_devices.k_lock);
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
if (dev->driver == drv)
__device_release_driver(dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
put_device(dev);
}
-------->void __device_release_driver(struct device *dev)
{
struct device_driver *drv;
drv = dev->driver;
if (drv) {
pm_runtime_get_noresume(dev);
pm_runtime_barrier(dev);
driver_sysfs_remove(dev);
if (dev->bus && dev->bus->remove)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
devres_release_all(dev);
dev->driver = NULL;
klist_remove(&dev->p->knode_driver);
pm_runtime_put_sync(dev);
}
}
我们知道:一个设备只能绑定一个驱动,而同一个驱动可以适用于多个设备(不用想就知道为什么)。所以第9行开始的for死循环就是遍历挂在driver上的device链表,直到链表为空,遍历完成退出for循环;否则,如果device的驱动是当前要卸载的驱动(dev->driver == drv),就调用__device_release_driver进行进一步操作。
在__device_release_driver函数中,pm_runtime_xxx之类的函数防止卸载过程中系统休眠,41行移除driver呈现在sys文件系统下的文件,44、45调用bus上的remove函数,而我们的主角-remove就在46、47行调用,进而执行s3cmci_remove函数。
现在,device没有驱动了,所以设置device的driver成员为NULL:
dev->driver = NULL
设备移除:
void platform_device_del(struct platform_device *pdev)
-->device_del(&pdev->dev)
---->bus_remove_device(dev)
{
if (dev->bus) {
sysfs_remove_link(&dev->kobj, "subsystem");
sysfs_remove_link(&dev->bus->p->devices_kset->kobj,
dev_name(dev));
device_remove_attrs(dev->bus, dev);
if (klist_node_attached(&dev->p->knode_bus))
klist_del(&dev->p->knode_bus);
pr_debug("bus: '%s': remove device %s\n",
dev->bus->name, dev_name(dev));
device_release_driver(dev);
bus_put(dev->bus);
}
}
------>device_release_driver(dev)
{
/*
* If anyone calls device_release_driver() recursively from
* within their ->remove callback for the same device, they
* will deadlock right here.
*/
device_lock(dev);
__device_release_driver(dev);
device_unlock(dev);
}
-------->__device_release_driver(dev)
第5行,翻译过来就是:移除bus上的设备。整个bus_remove_device函数也非常简单,删除sys文件系统与该设备相关的文件(链接)、删除设备的属性文件、完了通过bus_put减少device的引用计数(Decrement the refcount),当其引用计数为0的时候,才会彻底清楚该device及其占用的资源。
系统关机/重启流程:
void device_shutdown(void)
{
struct device *dev;
spin_lock(&devices_kset->list_lock);
/*
* Walk the devices list backward, shutting down each in turn.
* Beware that device unplug events may also start pulling
* devices offline, even as the system is shutting down.
*/
while (!list_empty(&devices_kset->list)) {
dev = list_entry(devices_kset->list.prev, struct device,
kobj.entry);
get_device(dev);
/*
* Make sure the device is off the kset list, in the
* event that dev->*->shutdown() doesn't remove it.
*/
list_del_init(&dev->kobj.entry);
spin_unlock(&devices_kset->list_lock);
if (dev->bus && dev->bus->shutdown) {
dev_dbg(dev, "shutdown\n");
dev->bus->shutdown(dev);
} else if (dev->driver && dev->driver->shutdown) {
dev_dbg(dev, "shutdown\n");
dev->driver->shutdown(dev);
}
put_device(dev);
spin_lock(&devices_kset->list_lock);
}
spin_unlock(&devices_kset->list_lock);
}
void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
device_shutdown();
sysdev_shutdown();
}
static void kernel_shutdown_prepare(enum system_states state)
{
blocking_notifier_call_chain(&reboot_notifier_list,
(state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
system_state = state;
device_shutdown();
}
这几个函数实现都简明易懂,再加上注释更加不在话下,25~28行调用shutdown函数s3cmci_shutdown。这地方简单是因为有之前的基础,所以说:提纲契领,举一反三。