PCI设备的注册过程分析1
来源:互联网 发布:rimworld mac 下载 编辑:程序博客网 时间:2024/04/29 01:15
R.wen
在2.6设备模型下,当一个驱动程序模块挂入内核(insmod),它会遍历所有在这个总线(BUS)上注册的设备链表,并且对每个被遍历的设备调用 match()函数,直到找到匹配的为止。第二种情况是,当一个设备被插入到系统总线上的时候(或系统初起),它会遍历枚举这个总线上的所有注册过的驱 动,并且对每个驱动调用match()函数,直到找到匹配的驱动为止。
之后,上两种情况都会调用probe函数,进行设备的初始化。
二、驱动注册过程。
首先是驱动的注册,以e100为例:
static struct pci_driver e100_driver = {
.name = DRV_NAME,
.id_table = e100_id_table,
.probe = e100_probe,
.remove = __devexit_p(e100_remove),
.shutdown = e100_shutdown,
……
};
static int __init e100_init_module(void)
{
return pci_register_driver(&e100_driver);
}
我们看到,它先初始化一个pci_driver结构,然后以这个结构为参数调用pci_register_driver(),它其实是:
static inline int __must_check pci_register_driver(struct pci_driver *driver)
{
return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
/**
* __pci_register_driver - register a new pci driver
* @drv: the driver structure to register
* @owner: owner module of drv
* @mod_name: module name string
*
* Adds the driver structure to the list of registered drivers.
* Returns a negative value on error, otherwise 0.
* If no error occurred, the driver remains registered even if
* no device was claimed during registration.
*/
int __pci_register_driver(struct pci_driver *drv, struct module *owner,
const char *mod_name)
{
int error;
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.owner = owner;
drv->driver.mod_name = mod_name;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
//是否使用多线程来进行probe
if (pci_multithread_probe)
drv->driver.multithread_probe = pci_multithread_probe;
else
drv->driver.multithread_probe = drv->multithread_probe;
spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list);
/* register with core */
error = driver_register(&drv->driver); //上面是PCI驱动的注册,这里是通用设备的注册
if (error)
return error;
//在sysfs中建立文件项
error = pci_create_newid_file(drv);
if (error)
driver_unregister(&drv->driver);
return error;
}
/**
* driver_register - register driver with bus
* @drv: driver to register
*
* We pass off most of the work to the bus_add_driver() call,
* since most of the things we have to do deal with the bus
* structures.
*
* The one interesting aspect is that we setup @drv->unloaded
* as a completion that gets complete when the driver reference
* count reaches 0.
*/
int driver_register(struct device_driver * drv)
{
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);
}
klist_init(&drv->klist_devices, NULL, NULL);
init_completion(&drv->unloaded);
return bus_add_driver(drv); //这个函数将驱动加入BUS链表
}
/**
* bus_add_driver - Add a driver to the bus.
* @drv: driver.
*/
int bus_add_driver(struct device_driver *drv)
{
struct bus_type * bus = get_bus(drv->bus);
int error = 0;
if (!bus)
return 0;
pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
error = kobject_set_name(&drv->kobj, "%s", drv->name);
if (error)
goto out_put_bus;
drv->kobj.kset = &bus->drivers;
if ((error = kobject_register(&drv->kobj)))
goto out_put_bus;
//将这个驱动与可能的设备捆绑起来
error = driver_attach(drv);
if (error)
goto out_unregister;
klist_add_tail(&drv->knode_bus, &bus->klist_drivers); //加入链表
module_add_driver(drv->owner, drv);
error = driver_add_attrs(bus, drv); //注册属性
……
return error;
}
/**
* driver_attach - try to bind driver to devices.
* @drv: driver.
*
* Walk the list of devices that the bus has on it and try to
* match the driver with each one. If driver_probe_device()
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*/
//这是个重要的函数,它会遍历设备链表,试图匹配这个总线上的设备
int driver_attach(struct device_driver * drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
static int __driver_attach(struct device * dev, void * data)
{
struct device_driver * drv = data;
if (dev->parent) /* Needed for USB */
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; //总是返回0
}
int bus_for_each_dev(struct bus_type * bus, struct device * start,
void * data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device * dev;
int error = 0;
if (!bus)
return -EINVAL;
klist_iter_init_node(&bus->klist_devices, &i,
(start ? &start->knode_bus : NULL));
while ((dev = next_device(&i)) && !error) //由于error总是0,所以会遍历整个链表
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
struct bus_type pci_bus_type = {
.name = "pci",
.match = pci_bus_match,
.uevent = pci_uevent,
.probe = pci_device_probe,
.remove = pci_device_remove,
.suspend = pci_device_suspend,
.suspend_late = pci_device_suspend_late,
.resume_early = pci_device_resume_early,
.resume = pci_device_resume,
.shutdown = pci_device_shutdown,
.dev_attrs = pci_dev_attrs,
};
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
struct stupid_thread_structure *data;
struct task_struct *probe_task;
int ret = 0;
if (!device_is_registered(dev)) //已经注册了
return -ENODEV;
if (drv->bus->match && !drv->bus->match(dev, drv))
goto done; //调用match()函数,如果不匹配,则说明这个驱动不合适这个设备,跳过这个设备。由上面的结构可以看到,这个函数是pci_bus_match
pr_debug("%s: Matched Device %s with Driver %s\n",
drv->bus->name, dev->bus_id, drv->name);
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->drv = drv;
data->dev = dev;
if (drv->multithread_probe) { //启动另一个线程来完成
probe_task = kthread_run(really_probe, data,
"probe-%s", dev->bus_id);
if (IS_ERR(probe_task))
ret = really_probe(data);
} else
ret = really_probe(data);
done:
return ret;
}
static int pci_bus_match(struct device *dev, struct device_driver *drv)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct pci_driver *pci_drv = to_pci_driver(drv);
const struct pci_device_id *found_id;
found_id = pci_match_device(pci_drv, pci_dev);
if (found_id)
return 1;
return 0; //不匹配
}
const struct pci_device_id *pci_match_device(struct pci_driver *drv,
struct pci_dev *dev)
{
struct pci_dynid *dynid;
/* Look at the dynamic ids first, before the static ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (pci_match_one_device(&dynid->id, dev)) {
spin_unlock(&drv->dynids.lock);
return &dynid->id;
}
}
spin_unlock(&drv->dynids.lock);
//检查静态表,这个表来自于pc_driver中的id_table域。
return pci_match_id(drv->id_table, dev);
}
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
struct pci_dev *dev)
{
if (ids) {
while (ids->vendor || ids->subvendor || ids->class_mask) {
if (pci_match_one_device(ids, dev))
return ids;
ids++;
}
}
return NULL;
}
static inline const struct pci_device_id *
pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
{
if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
(id->device == PCI_ANY_ID || id->device == dev->device) &&
(id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
(id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&
!((id->class ^ dev->class) & id->class_mask))
return id;
return NULL;
}
如果上面的match成功返回,下一步则执行以下这个函数了。
static int really_probe(void *void_data)
{
struct stupid_thread_structure *data = void_data;
struct device_driver *drv = data->drv;
struct device *dev = data->dev;
int ret = 0;
atomic_inc(&probe_count);
pr_debug("%s: Probing driver %s with device %s\n",
drv->bus->name, drv->name, dev->bus_id);
WARN_ON(!list_empty(&dev->devres_head));
dev->driver = drv; //将匹配的设备和驱动捆绑起来,这一步是关键
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__FUNCTION__, dev->bus_id);
goto probe_failed;
}
if (dev->bus->probe) {
ret = dev->bus->probe(dev); //执行总线的probe函数
if (ret)
goto probe_failed;
} else if (drv->probe) { //如果没有,则执行驱动的probe
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
driver_bound(dev);
ret = 1;
pr_debug("%s: Bound Device %s to Driver %s\n",
drv->bus->name, dev->bus_id, drv->name);
goto done;
probe_failed:
…...
ret = 0;
done:
kfree(data);
atomic_dec(&probe_count);
wake_up(&probe_waitqueue);
return ret;
}
由上面的结构可以看到,总线的probe是以下这个函数。
static int pci_device_probe(struct device * dev)
{
int error = 0;
struct pci_driver *drv;
struct pci_dev *pci_dev;
drv = to_pci_driver(dev->driver);
pci_dev = to_pci_dev(dev);
pci_dev_get(pci_dev);
error = __pci_device_probe(drv, pci_dev);
if (error)
pci_dev_put(pci_dev);
return error;
}
static int
__pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
{
const struct pci_device_id *id;
int error = 0;
if (!pci_dev->driver && drv->probe) {
error = -ENODEV;
id = pci_match_device(drv, pci_dev); //再次检查匹配
if (id)
error = pci_call_probe(drv, pci_dev, id);
if (error >= 0) {
pci_dev->driver = drv;
error = 0;
}
}
return error;
}
我们看到,总线的probe最终还是执行驱动程序提供的probe函数。至此,设备的注册过程已经完成。
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
const struct pci_device_id *id)
{
int error;
#ifdef CONFIG_NUMA
……
#endif
error = drv->probe(dev, id); //完成系统的初始化操作
#ifdef CONFIG_NUMA
……
#endif
return error;
}
三、设备的注册过程
当一个PCI设备热插拔,或是系统初启时,它会遍历这个总线的已经注册进内核里的驱动链表。当找到匹配的时候,它就将这个设备绑定。
它首先会执行一个注册函数:
int device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
int device_add(struct device *dev)
{
struct device *parent = NULL;
char *class_name = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
dev = get_device(dev);
if (!dev || !strlen(dev->bus_id))
goto Error;
pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
parent = get_device(dev->parent);
error = setup_parent(dev, parent);
if (error)
goto Error;
/* first, register with generic layer. */
kobject_set_name(&dev->kobj, "%s", dev->bus_id);
error = kobject_add(&dev->kobj);
if (error)
goto Error;
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
/* notify clients of device entry (new way) */
if (dev->bus) //通知链表
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
dev->uevent_attr.attr.name = "uevent";
dev->uevent_attr.attr.mode = S_IWUSR;
if (dev->driver)
dev->uevent_attr.attr.owner = dev->driver->owner;
dev->uevent_attr.store = store_uevent;
error = device_create_file(dev, &dev->uevent_attr);
if (error)
goto attrError;
if (MAJOR(dev->devt)) { //属性处理
struct device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) {
error = -ENOMEM;
goto ueventattrError;
}
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
if (dev->driver)
attr->attr.owner = dev->driver->owner;
attr->show = show_dev;
error = device_create_file(dev, attr);
if (error) {
kfree(attr);
goto ueventattrError;
}
dev->devt_attr = attr;
}
if (dev->class) { //设备类型处理
sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,
"subsystem");
/* If this is not a "fake" compatible device, then create the
* symlink from the class to the device. */
if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
sysfs_create_link(&dev->class->subsys.kset.kobj,
&dev->kobj, dev->bus_id);
if (parent) {
sysfs_create_link(&dev->kobj, &dev->parent->kobj,
"device");
#ifdef CONFIG_SYSFS_DEPRECATED
class_name = make_class_name(dev->class->name,
&dev->kobj);
if (class_name)
sysfs_create_link(&dev->parent->kobj,
&dev->kobj, class_name);
#endif
}
}
if ((error = device_add_attrs(dev)))
goto AttrsError;
if ((error = device_add_groups(dev)))
goto GroupError;
if ((error = device_pm_add(dev)))
goto PMError;
if ((error = bus_add_device(dev)))
goto BusError;
if (!dev->uevent_suppress)
kobject_uevent(&dev->kobj, KOBJ_ADD);
if ((error = bus_attach_device(dev))) //将设备于驱动绑定
goto AttachError;
if (parent) //加入链表
klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
down(&dev->class->sem);
/* tie the class to the device */
list_add_tail(&dev->node, &dev->class->devices);
/* notify any interfaces that the device is here */
list_for_each_entry(class_intf, &dev->class->interfaces, node)
if (class_intf->add_dev)
class_intf->add_dev(dev, class_intf);
up(&dev->class->sem);
}
Done:
kfree(class_name);
put_device(dev);
return error;
……
}
int bus_add_device(struct device * dev)
{
struct bus_type * bus = get_bus(dev->bus);
int error = 0;
if (bus) {
pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
error = device_add_attrs(bus, dev);
if (error)
goto out_put;
error = sysfs_create_link(&bus->devices.kobj,
&dev->kobj, dev->bus_id);
if (error)
goto out_id;
error = sysfs_create_link(&dev->kobj,
&dev->bus->subsys.kset.kobj, "subsystem");
if (error)
goto out_subsys;
error = make_deprecated_bus_links(dev);
if (error)
goto out_deprecated;
}
return 0;
out_deprecated:
sysfs_remove_link(&dev->kobj, "subsystem");
out_subsys:
sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
out_id:
device_remove_attrs(bus, dev);
out_put:
put_bus(dev->bus);
return error;
}
/**
* bus_attach_device - add device to bus
* @dev: device tried to attach to a driver
*
* - Add device to bus's list of devices.
* - Try to attach to driver.
*/
int bus_attach_device(struct device * dev)
{
struct bus_type *bus = dev->bus;
int ret = 0;
if (bus) {
dev->is_registered = 1;
ret = device_attach(dev);
if (ret >= 0) {
klist_add_tail(&dev->knode_bus, &bus->klist_devices);
ret = 0;
} else
dev->is_registered = 0;
}
return ret;
}
int device_attach(struct device * dev)
{
int ret = 0;
down(&dev->sem);
if (dev->driver) {
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
} else
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
up(&dev->sem);
return ret;
}
static int __device_attach(struct device_driver * drv, void * data)
{
struct device * dev = data;
return driver_probe_device(drv, dev);
}
接下来的代码就跟上面的驱动注册一样了。
- PCI设备的注册过程分析1
- PCI设备的注册过程分析
- intel dpdk api pci设备驱动注册和初始化过程
- intel dpdk api pci设备驱动注册和初始化过程
- 网卡驱动注册到PCI总线这一过程的分析
- 【转】网卡驱动注册到PCI总线这一过程的分析
- 网卡驱动注册到PCI总线这一过程的分析 [复制链接]
- 网卡驱动注册到PCI总线这一过程的分析一
- 网卡驱动注册到PCI总线这一过程的分析二
- 网卡驱动注册到PCI总线这一过程的分析
- 网卡驱动注册到PCI总线这一过程的分析一
- 网卡驱动注册到PCI总线这一过程的分析二
- PCI总线---PCI设备扫描过程
- 今天我以fb设备的注册过程来分析platform设备的添加流程
- 设备树学习之(七)I2C设备的注册过程分析
- 设备树学习之(七)I2C设备的注册过程分析
- 设备树学习之(七)I2C设备的注册过程分析
- PCI设备的初始化
- java 计算平均值,去除不合理的数据
- 设计模式之策略模式
- C++学习之基础变量及类型
- java集合之Map
- 娃娃出生记
- PCI设备的注册过程分析1
- 【Xcode】我的Xcode配置(不停更新)
- jedispool使用自动归还jedis解决方案
- Linux 搜索所有文件内容截取所需记录
- 建造者模式Builder
- Tensorflow的Eigen编程
- Android调用相机和相册
- java 根据图片的像素RBG值转换成文字符号
- 判断数组A是否包含数组B的某些元素Contains方法