了解一下热插拔
Ldd3的话:
现在, 随着 USB的出现, CardBus, PCMCIA,IEEE1394,和 PCI 热插拔控制器, Linux内核需要能够可靠地运行不管什么硬件从系统中增加或去除.这产生了一个额外的负担给设备驱动作者,因为现在他们必须一直处理一个没有任何通知而突然从地下冒出来的设备.
从这句话我们可以看出,热插拔有两个层次,一个是内核设备模型中提供的机制,一个是硬件提供的功能。
我们的实例主要是设备模型中提供的机制。硬件方面有时间的话我举个例子。
一些基础知识如udev和mdev我就不说了,论坛有。
还是linux-3.2.36
在kobject中有个结构struct kset_uevent_ops,我没有列出,因为总线已有这个结构,我们是在总线层所以不要去管理这个结构。
简单说一下热插拔过程(论坛也有这些分析)。
./drivers/base/core.c
device_register()->device_add()->kobject_uevent()->
./lib/ kobject_uevent.c
kobject_uevent_env()->call_usermodehelper()和netlink_broadcast_filtered()
一个是uevent_helper调用一个是netlink调用,这两个东西又够我写几遍文章了,等有时间我再写吧。现在简单了解。
netlink是为udev实现机制用的
uevent_helper是为mdev实现机制用的
我的arm平台用的是mdev
call_usermodehelper()第一个参数叫path
path --- 用户空间所要启用的应用程序路径
用mdev时,会echo “/sbin/mdev”> /proc/sys/kernel/hotplug把uevent_helper改为“/sbin/mdev”,再把uevent_helper赋给call_usermodehelper(),最终调用mdev。
说实例之前,先说一下mdev配置。//用udev的同学自己搞定,我就不说了
# vi /etc/mdev.conf
$MODALIAS=.* root:root777 @modprobe "$MODALIAS"
保存
MODALIAS要和驱动中一致,马上能看到。
这条规则指的是:当收到的环境变量中含有MODALIAS,那么加载MODALIAS代表的模块。
实例:
这个是在上一文章的实例基础上做的,如果要了解,你还要先简单了解一下上一实例(设备模型5)。
在my_dev.c中修改,我们要答到的目的是加载my_dvc.ko时自动加载my_dvr.ko
修改,红色为增加
MODULE_DEVICE_TABLE(my_dvc, my_dvc_table);
static ssize_t show_name(struct device *dev, structdevice_attribute *attr, char *buf)
{
struct my_device*mydev = (struct my_device*)dev->platform_data;
return sprintf(buf,"%s\n", mydev->name);
}
static ssize_t show_modalias(struct device *dev, structdevice_attribute *attr, char *buf)
{
return sprintf(buf,"%s\n", "my_dvr");
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
//这两个文件只是为了输出一些信息,可以不管
static struct attribute *my_dvc_attrs[] = {
&dev_attr_name.attr,
&dev_attr_modalias.attr,
NULL
};
static struct attribute_group my_dvc_attr_group =
{
.attrs = my_dvc_attrs,
};
static const struct attribute_group *my_dvc_attr_groups[] =
{
&my_dvc_attr_group,
NULL
};
static int my_dvc_uevent(struct device *dev, structkobj_uevent_env *env)
{
struct my_device*mydev = (struct my_device*)dev->platform_data;
int i = 0;
MY_DEBUG("%s_uevent\n",mydev->name);
//实际一般用一些方法获得driver的name,这里就直接写了
if(add_uevent_var(env, "MODALIAS=%s", "my_dvr"))// MODALIAS和mdev.conf一致
return -ENOMEM;
while(env->envp[i]!= NULL)//我们做一个调试信息
{
MY_DEBUG("%s\n",env->envp[i]);//打印环境变量