日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 驱动没有设备id,linux不同总线的设备和驱动的匹配过程分析

發布時間:2023/12/9 linux 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 驱动没有设备id,linux不同总线的设备和驱动的匹配过程分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

摘自:

前幾日讀書會,談到linux中driver和device的匹配問題,我認為是通過設備名來匹配的,因為我之前看過platform的驅動,它就是通過設備name和驅動name來進行匹配,所以我確信linux里邊所有的驅動和設備都是這樣匹配的。但師兄A提出了反對意見,并舉pci設備和pci驅動的匹配過程為例。我深信自己的理解是正確的,下來以后分秒必爭的查看了內核源代碼,結果發現:我們的理解都是正確的,但又都是不正確的!

先以pci設備和pci驅動的匹配過程為例:

static struct pci_driver serial_pci_driver = {

.name?????????? = "serial",

.probe????????? = pciserial_init_one,

.remove???????? = __devexit_p(pciserial_remove_one),

#ifdef CONFIG_PM

.suspend??????? = pciserial_suspend_one,

.resume???????? = pciserial_resume_one,

#endif

.id_table?????? = serial_pci_tbl,

};

static int __init serial8250_pci_init(void)

{

return pci_register_driver(&serial_pci_driver);

}

分析:

#define pci_register_driver(driver)???????????? \

__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

int __pci_register_driver(struct pci_driver *drv, struct module *owner,

const char *mod_name)

{

...

drv->driver.bus = &pci_bus_type;

error = driver_register(&drv->driver);

...

}

僅僅抓取兩句關鍵代碼,后面會用到

driver_register ->? bus_add_driver ->? driver_attach(&driver->driver);

int driver_attach(struct device_driver *drv)

{

return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

//遍歷總線上的所有設備,每遍歷一個設備,就調用一次__driver_attach來和驅動進行匹配

}

static int __driver_attach(struct device *dev, void *data)

{

struct device_driver *drv = data;

/*

* 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.

*/

if (drv->bus->match && !drv->bus->match(dev, drv))

return 0;

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;

}

我最關注的是這句代碼:

if (drv->bus->match && !drv->bus->match(dev, drv))

return 0;

這句代碼揭露了匹配的過程。

這是一種面向對像的思想,你是pci設備,那就調用pci總線的match函數;你是其他總線的設備

那就調用相應的其他的match函數。由于我們是pci的驅動(我們注冊驅動使用的函數是pci_register_driver)并且在前面有:

drv->driver.bus = &pci_bus_type;讓我們看看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_attrs????? = pci_dev_attrs,

.pm???????????? = PCI_PM_OPS_PTR,

};

很明顯,我們將進入pci_bus_match

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);//對pci驅動和設備進行匹配

if (found_id)

return 1;

return 0;

}

static 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);

return pci_match_id(drv->id_table, dev);

}

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;

}

這就是具體的匹配過程,這個過程大家看代碼應該可以明白。

假如匹配,那么會返回一個pci_device_id類型的指針。

在__driver_attach函數里邊繼續往下看,有一句:

if (!dev->driver)

driver_probe_device(drv, dev);

假如 這個設備還沒有“名花有主”,那么調用driver_probe_device

int driver_probe_device(struct device_driver *drv, struct device *dev)

{

int ret = 0;

if (!device_is_registered(dev))

return -ENODEV;

if (drv->bus->match && !drv->bus->match(dev, drv))

goto done;

pr_debug("bus: '%s': %s: matched device %s with driver %s\n",

drv->bus->name, __func__, dev_name(dev), drv->name);

ret = really_probe(dev, drv);

done:

return ret;

}

static int really_probe(struct device *dev, struct device_driver *drv)

{

...

if (dev->bus->probe) {

ret = dev->bus->probe(dev);

if (ret)

goto probe_failed;

} else if (drv->probe) {

ret = drv->probe(dev);????????? //終于進入了我們注冊的驅動的probe函數

if (ret)

goto probe_failed;

}

...

}

總結一下,pci驅動和pci設備的匹配不是通過名字來進行匹配的,具體過程上面已經說清楚了。而且,通過上面的分析,大家可以看出來

內核使用的是面向對象的思想,不同的總線它的匹配策略是不一樣的。

附:

1.platform總線的匹配策略:

static int platform_match(struct device *dev, struct device_driver *drv)

{

struct platform_device *pdev;

pdev = container_of(dev, struct platform_device, dev);

return (strcmp(pdev->name, drv->name) == 0);

}

可見platform總線設備和驅動的匹配策略很簡單,僅僅是比較name域是否相同

2.usb總線的匹配策略:

static int usb_device_match(struct device *dev, struct device_driver *drv)

{

/* devices and interfaces are handled separately */

if (is_usb_device(dev)) {

/* interface drivers never match devices */

if (!is_usb_device_driver(drv))

return 0;

/* TODO: Add real matching code */

return 1;

} else {

struct usb_interface *intf;

struct usb_driver *usb_drv;

const struct usb_device_id *id;

/* device drivers never match interfaces */

if (is_usb_device_driver(drv))

return 0;

intf = to_usb_interface(dev);

usb_drv = to_usb_driver(drv);

id = usb_match_id(intf, usb_drv->id_table);

if (id)

return 1;

id = usb_match_dynamic_id(intf, usb_drv);

if (id)

return 1;

}

return 0;

}

usb總線設備和驅動的匹配策略則比較復雜。

摘自:

閱讀(2861) | 評論(0) | 轉發(0) |

總結

以上是生活随笔為你收集整理的linux 驱动没有设备id,linux不同总线的设备和驱动的匹配过程分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。