1.1 初始化驱动函数

在rtcan_adv_pci.c中
adv_pci驱动程序的初始化函数module_init(rtcan_adv_pci_init):

static int __init rtcan_adv_pci_init(void)
{if (!realtime_core_enabled())return 0;return pci_register_driver(&rtcan_adv_pci_driver);
}

在这个函数中,调用了pci_register_driver()函数,对rtcan_adv_pci_driver这个驱动进行注册

1.2 PCI注册

在前面我们已经看到,PCI的注册就是将PCI驱动程序挂载到其所在的总线的drivers链,同时扫描PCI设备,将它能够进行驱动的设备挂载到driver上的devices链表上来,这里,我们将详细地查看这整个流程的函数调用关系。pci_register_driver()->__pci_register_driver()  //注意:这可是2个不同的函数
/** pci_register_driver must be a macro so that KBUILD_MODNAME can be expanded*/
#define pci_register_driver(driver)     \__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)
{/* 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;spin_lock_init(&drv->dynids.lock);INIT_LIST_HEAD(&drv->dynids.list);/* register with core */return driver_register(&drv->driver);
}

即是将PCI设备中的driver变量的总线指向pci_bus_type这个总线描述符,同时设置驱动的名字等。

   struct bus_type pci_bus_type = {.name        = "pci",.match       = pci_bus_match,.uevent        = pci_uevent,.probe        = pci_device_probe,.remove     = pci_device_remove,.shutdown  = pci_device_shutdown,.dev_groups  = pci_dev_groups,.bus_groups   = pci_bus_groups,.drv_groups   = pci_drv_groups,.pm       = PCI_PM_OPS_PTR,
};

然后再调用函数driver_register(&drv->driver);通过这个函数将这个PCI驱动中的struct device_driver driver成员变量注册到系统中去。就是说将这个PCI设备驱动注册到PCI总线的描述符的driver链中。
pci_register_driver()->__pci_register_driver()->driver_register()
driver_register()代码如下:

/*** 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.*/
int driver_register(struct device_driver *drv)
{int ret;struct device_driver *other;BUG_ON(!drv->bus->p);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) {printk(KERN_ERR "Error: Driver '%s' is already registered, ""aborting...\n", drv->name);return -EBUSY;}ret = bus_add_driver(drv);if (ret)return ret;ret = driver_add_groups(drv, drv->groups);if (ret) {bus_remove_driver(drv);return ret;}kobject_uevent(&drv->p->kobj, KOBJ_ADD);return ret;
}

最后就调用bus_add_driver()函数。这个函数的功能就是将这个驱动加到其所在的总线的驱动链上。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()
在bus_add_driver()函数中,最重要的是调用driver_attach()函数,其定义如下:


```c
/*** bus_add_driver - Add a driver to the bus.* @drv: driver.*/
int bus_add_driver(struct device_driver *drv)
{struct bus_type *bus;struct driver_private *priv;int error = 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;goto out_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)goto out_unregister;klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);if (drv->bus->p->drivers_autoprobe) {if (driver_allows_async_probing(drv)) {pr_debug("bus: '%s': probing driver %s asynchronously\n",drv->bus->name, drv->name);async_schedule(driver_attach_async, drv);} else {error = driver_attach(drv);if (error)goto out_unregister;}}module_add_driver(drv->owner, drv);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_groups(drv, bus->drv_groups);if (error) {/* How the hell do we get out of this pickle? Give up */printk(KERN_ERR "%s: driver_create_groups(%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);}}return 0;out_unregister:kobject_put(&priv->kobj);kfree(drv->p);drv->p = NULL;
out_put_bus:bus_put(bus);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);
}
       driver_attach()函数遍历这个驱动所在的总线上的所有设备,然后将这些设备与当前驱动进行匹配,以检测判断这个驱动是否能够支持某个设备,也即是将设备与驱动联系起来。bus_for_each_dev函数是扫描在drv->bus这个总线上的所有设备,然后将每个设备以及当前驱动这两个**指针**传递给__driver_attach函数。pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()__driver_attach()函数是将驱动与设备联系起来的函数。```c
/*** bus_for_each_dev - device iterator.* @bus: bus type.* @start: device to start iterating from.* @data: data for the callback.* @fn: function to be called for each device.** Iterate over @bus's list of devices, and call @fn for each,* passing it @data. If @start is not NULL, we use that device to* begin iterating from.** We check the return of @fn each time. If it returns anything* other than 0, we break out and return that value.** NOTE: The device that returns a non-zero value is not retained* in any way, nor is its refcount incremented. If the caller needs* to retain this data, it should do so, and increment the reference* count in the supplied callback.*/
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 || !bus->p)return -EINVAL;klist_iter_init_node(&bus->p->klist_devices, &i,(start ? &start->p->knode_bus : NULL));while ((dev = next_device(&i)) && !error)error = fn(dev, data);klist_iter_exit(&i);return error;
}

这个klist_devices是一个对链表进行操作的包裹结构,它会链接这个驱动能够支持的那些设备。这里的fn就是__driver_attach函数,我们来看一下它干了什么:

static int __driver_attach(struct device *dev, void *data)
{struct device_driver *drv = data;int ret;/** Lock device and try to bind to it. We drop the error* here and always return 0, because we need to keep trying* to bind to devices and some drivers will return an error* simply if it didn't support the device.** driver_probe_device() will spit a warning if there* is an error.*/ret = driver_match_device(drv, dev);if (ret == 0) {/* no match */return 0;} else if (ret == -EPROBE_DEFER) {dev_dbg(dev, "Device match requests probe deferral\n");driver_deferred_probe_add(dev);} else if (ret < 0) {dev_dbg(dev, "Bus failed to match device: %d", ret);return ret;} /* ret > 0 means positive match */if (dev->parent)  /* Needed for USB */device_lock(dev->parent);device_lock(dev);if (!dev->driver)driver_probe_device(drv, dev);device_unlock(dev);if (dev->parent)device_unlock(dev->parent);return 0;
}

driver_match_device函数就是用来为driver匹配device的

static inline int driver_match_device(struct device_driver *drv,struct device *dev)
{return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

这里开始调用device_driver中注册的match函数来进行匹配了,匹配的具体过程就不看了。再回到上面的__driver_attach函数的driver_probe_device中。
函数中有两条语句 :

if (!dev->driver)driver_probe_device(drv, dev);

也即是判断当前设备是否已经注册了一个驱动,如果没有注册驱动,则调用driver_probe_device()函数。
pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()
如下:

/*** driver_probe_device - attempt to bind device & driver together* @drv: driver to bind a device to* @dev: device to try to bind to the driver** This function returns -ENODEV if the device is not registered,* 1 if the device is bound successfully and 0 otherwise.** This function must be called with @dev lock held.  When called for a* USB interface, @dev->parent lock must be held as well.** If the device has a parent, runtime-resume the parent before driver probing.*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{int ret = 0;if (!device_is_registered(dev))return -ENODEV;pr_debug("bus: '%s': %s: matched device %s with driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name);if (dev->parent)pm_runtime_get_sync(dev->parent);pm_runtime_barrier(dev);ret = really_probe(dev, drv);pm_request_idle(dev);if (dev->parent)pm_runtime_put(dev->parent);return ret;
}
在该函数最后将调用really_probe函数。将device_driver与device结构体指针作为参数传递到这个函数中。下面几行是调用驱动或者总线的probe函数来扫描设备。pci_register_driver()->__pci_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->really_probe()really_probe()函数:

static int really_probe(struct device *dev, struct device_driver *drv)
{int ret = -EPROBE_DEFER;int local_trigger_count = atomic_read(&deferred_trigger_count);bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) &&!drv->suppress_bind_attrs;if (defer_all_probes) {/** Value of defer_all_probes can be set only by* device_defer_all_probes_enable() which, in turn, will call* wait_for_device_probe() right after that to avoid any races.*/dev_dbg(dev, "Driver %s force probe deferral\n", drv->name);driver_deferred_probe_add(dev);return ret;}atomic_inc(&probe_count);pr_debug("bus: '%s': %s: probing driver %s with device %s\n",drv->bus->name, __func__, drv->name, dev_name(dev));WARN_ON(!list_empty(&dev->devres_head));re_probe:dev->driver = drv;/* If using pinctrl, bind pins now before probing */ret = pinctrl_bind_pins(dev);if (ret)goto pinctrl_bind_failed;if (driver_sysfs_add(dev)) {printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",__func__, dev_name(dev));goto probe_failed;}if (dev->pm_domain && dev->pm_domain->activate) {ret = dev->pm_domain->activate(dev);if (ret)goto probe_failed;}/** Ensure devices are listed in devices_kset in correct order* It's important to move Dev to the end of devices_kset before* calling .probe, because it could be recursive and parent Dev* should always go first*/devices_kset_move_last(dev);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;}if (test_remove) {test_remove = false;if (dev->bus->remove)dev->bus->remove(dev);else if (drv->remove)drv->remove(dev);devres_release_all(dev);driver_sysfs_remove(dev);dev->driver = NULL;dev_set_drvdata(dev, NULL);if (dev->pm_domain && dev->pm_domain->dismiss)dev->pm_domain->dismiss(dev);pm_runtime_reinit(dev);goto re_probe;}pinctrl_init_done(dev);if (dev->pm_domain && dev->pm_domain->sync)dev->pm_domain->sync(dev);driver_bound(dev);ret = 1;pr_debug("bus: '%s': %s: bound device %s to driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name);goto done;probe_failed:if (dev->bus)blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_DRIVER_NOT_BOUND, dev);
pinctrl_bind_failed:devres_release_all(dev);driver_sysfs_remove(dev);dev->driver = NULL;dev_set_drvdata(dev, NULL);if (dev->pm_domain && dev->pm_domain->dismiss)dev->pm_domain->dismiss(dev);pm_runtime_reinit(dev);switch (ret) {case -EPROBE_DEFER:/* Driver requested deferred probing */dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name);driver_deferred_probe_add(dev);/* Did a trigger occur while probing? Need to re-trigger if yes */if (local_trigger_count != atomic_read(&deferred_trigger_count))driver_deferred_probe_trigger();break;case -ENODEV:case -ENXIO:pr_debug("%s: probe of %s rejects match %d\n",drv->name, dev_name(dev), ret);break;default:/* driver matched but the probe failed */printk(KERN_WARNING"%s: probe of %s failed with error %d\n",drv->name, dev_name(dev), ret);}/** Ignore errors returned by ->probe so that the next driver can try* its luck.*/ret = 0;
done:atomic_dec(&probe_count);wake_up(&probe_waitqueue);return ret;
}

其中
//1.先是调用的驱动所属总线的probe函数:
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
//2.再调用自己驱动中的probe函数:
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
此时的dev->bus为pci_bus_type,其probe函数则对应为:pci_device_probe。 drv->probe自己驱动中的函数
最后回驱动函数rtcan_adv_pci.c中
在rtcan_adv_pci.c中

static struct pci_driver rtcan_adv_pci_driver = {.name = RTCAN_DRV_NAME,.id_table = adv_pci_tbl,.probe = adv_pci_init_one,.remove = adv_pci_remove_one,
};
static int adv_pci_init_one(struct pci_dev *pdev,const struct pci_device_id *ent)
{int ret, channel;unsigned int nb_ports = 0;unsigned int bar = 0;unsigned int bar_flag = 0;unsigned int offset = 0;unsigned int ix;struct rtcan_device *master_dev = NULL;dev_info(&pdev->dev, "RTCAN Registering card");ret = pci_enable_device(pdev);if (ret)goto failure;dev_info(&pdev->dev, "RTCAN detected Advantech PCI card at slot #%i\n",PCI_SLOT(pdev->devfn));ret = pci_request_regions(pdev, RTCAN_DRV_NAME);if (ret)goto failure_device;switch (pdev->device) {case 0xc001:case 0xc002:case 0xc004:case 0xc101:case 0xc102:case 0xc104:nb_ports = pdev->device & 0x7;offset = 0x100;bar = 0;break;case 0x1680:case 0x2052:nb_ports = 2;bar = 2;bar_flag = 1;break;case 0x1681:nb_ports = 1;bar = 2;bar_flag = 1;break;default:goto failure_regions;}if (nb_ports > 1)channel = CHANNEL_MASTER;elsechannel = CHANNEL_SINGLE;RTCAN_DBG("%s: Initializing device %04x:%04x:%04x\n",RTCAN_DRV_NAME,pdev->vendor,pdev->device,pdev->subsystem_device);ret = rtcan_adv_pci_add_chan(pdev, channel, bar, offset, &master_dev);if (ret)goto failure_iounmap;/* register slave channel, if any */for (ix = 1; ix < nb_ports; ix++) {ret = rtcan_adv_pci_add_chan(pdev,CHANNEL_SLAVE,bar + (bar_flag ? ix : 0),offset * ix,&master_dev);if (ret)goto failure_iounmap;}pci_set_drvdata(pdev, master_dev);return 0;failure_iounmap:if (master_dev)rtcan_adv_pci_del_chan(pdev, master_dev);failure_regions:pci_release_regions(pdev);failure_device:pci_disable_device(pdev);failure:return ret;
}

驱动程序遍历总线上的struct device和struct device_driver两条链表,调用总线的match函数,对设备与驱动程序进行匹配。如果设备与驱动程序匹配成功,则调用驱动程序的probe函数。
至此Advantech PCI card设备驱动注册 初始化完成。

Advantech PCI card 驱动注册 --W T相关推荐

  1. Pci设备驱动:设备枚举

    有了设备模型基础及usb设备驱动的基础知识,来了解PCI设备驱动,就相对简单了,因为PCI设备驱动仍然套用了设备驱动模型的方式,用到的仍然是设备模型的相应函数,只是把相应的pci设备挂载到PCI总线的 ...

  2. [驱动注册]platform_driver_register()与platform_device_register()

    [驱动注册]platform_driver_register()与platform_device_register()      设备与驱动的两种绑定方式:在设备注册时进行绑定及在驱动注册时进行绑定. ...

  3. linux Pci字符驱动基本加载流程

    今天有朋友问我linux系统Pci字符驱动加载流程,简单整理了一下,顺便做个记录. 首先说下需要包含的头文件: 一个完整的字符驱动一般包含下面这些头文件: #include <linux/typ ...

  4. linux pci/pcie驱动

    /driver/pci/probe.c /arch/powerpc/kernel/pci_64.c 在pci驱动中pci调用pci_scan_device扫描每个设备的每个功能,当发现该功能存在时(通 ...

  5. Linux源码阅读——PCI总线驱动代码(一)整体框架

    目录 一.前言 二.概述 三.整体流程 四.PCI相关入口函数 4.1 pcibus_class_init 4.2 pci_driver_init 4.3 pci_arch_init 4.4 pci_ ...

  6. linux pci串口驱动下载,PCI串行口驱动下载_PCI串行口驱动官方下载-太平洋下载中心...

    PCI card Driver installation 驱动支持 SUPPORT:NT40/98/ME/2K/XP/VISTA/SERVER 驱动安装: 1.请选择卡的类型; 2.点击按钮进行驱动安 ...

  7. Linux源码阅读——PCI总线驱动代码(三)PCI设备枚举过程

    目录 前言 1.枚举过程 1.1 acpi_pci_root_add 1.2 pci_acpi_scan_root(枚举开始) 1.3 acpi_pci_root_create 1.4 pci_sca ...

  8. linux PCI设备驱动

    1.PCI 简介 1.1 PCI 引脚 为处理数据.寻址.接口控制.仲裁以及系统功能,PC接口作为目标设备的设备至少有47条引脚.作为总线主设备的设备至少有49条引脚.必要的引脚在左边,任选的引脚在右 ...

  9. PCI设备驱动与虚拟网卡驱动源码分析

    虚拟网卡驱动例程 #include<linux/module.h> #include<linux/sched.h> #include<linux/kernel.h> ...

最新文章

  1. LeetCode中等题之两两交换链表中的节点
  2. 互联网架构师必备技术 Docker仓库与Java应用服务动态发布那些事
  3. Android Studio引入.so文件的正确姿势 以及调用.so 文件时报错has text relocations 解决
  4. JavaScript模板引擎原理,几行代码的事儿
  5. 突破冰箱局限!海尔智家AWE发布美食物联生态平台
  6. MySQL Fabric 实践
  7. (计算机组成原理)第三章存储系统-第四节:主存储器和CPU的连接
  8. POP-一个点击带有放大还原的动画效果
  9. 牛客国庆集训派对Day3: G. Stones(博弈+SG)
  10. basic语言基础 chm_拒付论文装订费错失博士学位,C语言之父毕业论文丢失52年重见天日...
  11. 【记得交作业】波波离散实验报告一(python实现)
  12. 五笔打字--思成五笔秘方
  13. 5e检索服务器信息,服务器检索 - 找服玩|Minecraft服务器列表
  14. line 1 appears to contain embedded nulls
  15. python计算实例_python实例: 税率计算
  16. 利用注册表清除Office Word文档杀手病毒
  17. External Storage
  18. Idea中maven项目热部署,这么好用的IDE怎么会没有热部署,别傻了
  19. qq免费透明FLASH式漂浮物代码
  20. python读取pdf文件

热门文章

  1. IDEA 在DEBUG模式下如何不执行后续代码直接停止程序?
  2. R语言read.csv()读入行不规则数据
  3. 获取微信小程序的APPID及任意一个页面的路径信息
  4. 人脸扫描建模_一种基于三维扫描数据的人脸建模方法
  5. java 气泡_JAVA实现聊天气泡
  6. 实践篇·让你的图片特别起来—自定义像素化
  7. python按字典顺序输出单词频率_用python编写一段程序,输入若干单词,按照单词长短进行排序,并统计所有单词中每个字母(a-z)出现的次数...
  8. Windows系统使用开源工具scrcpy投屏
  9. Taro 和 uni-app选型对比
  10. AGV调式之软件开发—API调用