理所當(dāng)然,我們需要開始分析usb host controller了。 位置linux-2.6.32.21/drivers/usb/host,哇塞,怎么這么多xhci啊,什么ehci,uhci,fhci甚至還真的有xhci,看來搞host controller的人,自已都絕了索性以x來命名了。其實walfred查過資料之后才發(fā)現(xiàn),或許readme其實早就有提示(請看USB子系統(tǒng)學(xué)習(xí)二中的readme相關(guān)部分),這些眾多的hci只有ehci和uhci和ohci才是pc上用到的,其他是屬于嵌入式系統(tǒng)使用的。那么就算現(xiàn)在我們需要學(xué)習(xí)ehci和ochi和uhci也不輕松,它們之間是什么關(guān)系呢?請別著急,我會娓娓道來。 先看下host controller的作用。見下圖,ldd上有一句話說的很好,我決定引用過來“l(fā)inux內(nèi)核支持兩種主要類型的USB驅(qū)動程序:宿主(host)系統(tǒng)上的驅(qū)動程序和設(shè)備(device)上的驅(qū)動程序。從宿主的觀點來看(一個普通的USB宿主是一個桌面計算機),宿主系統(tǒng)的USB驅(qū)動程序控制插入其中的USB設(shè)備,而USB設(shè)備的驅(qū)動程序則控制該設(shè)備如何作為一個USB驅(qū)動和主機通信”,這一句話就道出來,我們率先學(xué)習(xí)宿主(host controller)的重要性。 那么內(nèi)核驅(qū)動文件中driver/usb/host看到的ehci ohci uhci,雜7雜8的,都有什么用,都是干嘛的呢? 1 名字解釋 uhci(universal host controller interface): Intel用在自家芯片組上的usb 1.1主控制器(host controller)的硬件實例。 ehci(enhanced host controller interface): usb 2.0的主控制器標(biāo)準(zhǔn)接口。 ohci(open host controller inferface):一個不僅僅是usb用的主控制器接口標(biāo)準(zhǔn),下面細(xì)分為usb,1394,或者更多(別的沒有接觸過)。主要是遵循csr (configuration space register)標(biāo)準(zhǔn)(另一個標(biāo)準(zhǔn),呵呵)。是其他廠商在設(shè)計usb host controller時遵循的標(biāo)準(zhǔn),如via, nec, ali, 包括nvidia等等。 2 相關(guān)特性 uhci, ohci在硬件實現(xiàn)以及對底層軟件訪問上都有所不同,但二者又都完全(實際上各自多少都有些不足)支持usb 1.1 specification里邊對usb host controller的要求。 同理,ehci是滿足usb 2.0 specification里面對usb host controller (high speed)的要求的硬件設(shè)計。 應(yīng)該是從win98之后usb1.1就被廣泛支持了,無論是uhci還是ohci。但ms真正支持usb2.0(或者說ehci)是從win2k sp4和winxp sp1。這里所說的真正支持是指系統(tǒng)自帶ehci的驅(qū)動而不需要第三方的驅(qū)動程序。 另外apple現(xiàn)在胳膊拗不過大腿,在mac機上也已經(jīng)都開始支持usb1.1和2.0接口。而上面的host controller一定是ohci的標(biāo)準(zhǔn)。謹(jǐn)以此獻給退居二線的喬老板。 3 他們的規(guī)格 uhci ohci ehci他們都是主機控制器的規(guī)格 OHCI主要為非PC系統(tǒng)上以及帶有SiShe ALi芯片組的PC主板上的USB芯片 UHCI大多為Intel和Via主板上的USB控制器芯片。UHCI的硬件電路比OHCI簡單,成本稍低,但驅(qū)動復(fù)雜。但他們都是由USB1.1規(guī)格的。 EHCI是有Intel等幾個廠商研發(fā),兼容OHCI UHCI 遵循USB2.0規(guī)范。 USB規(guī)范都是從寄存器級別規(guī)定好的,不過各個廠商可能有自己的幾個專用的寄存器。 4 有用的東東 usb 2.0 定義了低速(low speed),全速(full speed),高速(high speed)傳輸。EHCI 僅僅支持高速傳輸,所以它必須還要有一個 companion HC,如(UHCI)來支持低速和全速設(shè)備,情況時這樣的: 1), fs/ls 設(shè)備插入到 root hub port,會由 companion HC(uhci/ohci)發(fā)現(xiàn)并管理設(shè)備; 2),fs/ls 設(shè)備插入到 usb 2.0 hub(not root hub),那么由 ehci 通過 split transaction 和 transaction translation(tt)支持 fs/ls 設(shè)備。在usb core層會說到這個tt的。 比如,當(dāng)一個 usb 設(shè)備插入 root hub port 時,先要做一件 routing 的事情。所有的 root hub port默認(rèn)是被 EHCI 占有的,所以,EHCI 和插入的 usb 設(shè)備通信,看是不是 hs 設(shè)備,如果是好說。如果不是,EHCI 就放棄這個 port 的占有權(quán),讓給 companion HC(uhci/ohci)去管理。
USB子系統(tǒng)學(xué)習(xí)之EHCI(EHCI的使命)既然上一節(jié)USB子系統(tǒng)學(xué)習(xí)之基礎(chǔ)篇三(host controller)提到了我們需要擒賊先擒王,先向host controller下手,我們相信跟著本博客走,肯定是不會有錯的,不過一旦有問題,也被來找walfred,walfred只是一個喜歡更新OurUnix的博客控而已。順便提下本博的廣告語,OurUnix--一個分享嵌入式,Linux新技術(shù)的平臺。這年頭,廣告真是無孔不入呀!汗~~ 仍然停在USB HC階段 這邊再補充下,維基上面介紹HCD的一段話: 包含主機控制器和根HUB的硬件為程序員提供了由硬件實現(xiàn)定義的接口主機控制器設(shè)備 (HCD)。而實際上它在計算機上就是端口和內(nèi)存映射。 1.0和1.1的標(biāo)準(zhǔn)有兩個競爭的HCD實現(xiàn)??蛋氐拈_放主機控制器接口(OHCI)和Intel的通用主機控制器接口(UHCI)。VIA威盛采納了UHCI;其他主要的芯片組多使用OHCI。它們的主要區(qū)別是UHCI更加依賴軟件驅(qū)動,因此對CPU要求更高,但是自身的硬件會更廉價。它們的并存導(dǎo)致操作系統(tǒng)開發(fā)和硬件廠商都必須在兩個方案上開發(fā)和測試,從而導(dǎo)致費用上升。因此USB-IF在USB2.0的設(shè)計階段堅持只能有一個實現(xiàn)規(guī)范,這就是擴展主機控制器接口(EHCI)。因為EHCI只支持高速傳輸,所以EHCI控制器包括四個虛擬的全速或者慢速控制器。這里同樣是Intel和Via使用虛擬UHCI,其他一般使用OHCI控制器。 某些版本的Windows上,打開設(shè)備管理器,如果設(shè)備說明中是否有“增強”("Enhanced"),就能夠確認(rèn)它是2.0版的。而在Linux系統(tǒng)中,命令lspci能夠列出所有的PCI設(shè)備,而USB會分別命名為OHCI、UHCI或者EHCI。 那我們就用電腦試試看撒。 walfred@ubuntu:~/Documents/other/usb$ lspci 00:1d.0 USB Controller: Intel Corporation N10/ICH7 Family USB UHCI Controller #1 (rev 01) 00:1d.1 USB Controller: Intel Corporation N10/ICH 7 Family USB UHCI Controller #2 (rev 01) 00:1d.2 USB Controller: Intel Corporation N10/ICH 7 Family USB UHCI Controller #3 (rev 01) 00:1d.3 USB Controller: Intel Corporation N10/ICH 7 Family USB UHCI Controller #4 (rev 01) 00:1d.7 USB Controller: Intel Corporation N10/ICH 7 Family USB2 EHCI Controller (rev 01) 那現(xiàn)在我們在lsusb看看,是不是應(yīng)該有4個USB1.1(1.0)接口和1個USB2.0接口。 walfred@ubuntu:~/Documents/other/usb$ lsusb Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub 果真,猜測成功!我這可是真正的猜測成功,而不是前兩天在上海出現(xiàn)了,類“UFO”的天體,各方專家各顯神通的猜測,紫金山派認(rèn)準(zhǔn)即是真UFO,其它門派立即辟謠。各自猜測,卻沒有任何結(jié)論。。。 插播一則報道: 2011年8月23日,中國科學(xué)院紫金山天文臺研究員王思潮對記者介紹他的判斷:“這是一起重大UFO事件,不明飛行物是特殊的空間飛行器,用人類的飛行器很難解釋。該飛行器高度是在空間,和楊利偉飛船高度差不多,飛得很慢。”此前有天文專家指出,20日晚多地觀測到的UFO是“正處于噴火狀態(tài)的推進火箭,由于推力不平衡產(chǎn)生如此現(xiàn)象?!?/p> 蛋疼,這邊講USB,怎么扯到PCI上面去了,現(xiàn)在心中有疑惑,為什么維基上面會提示我們使用lspci呢,原來我們現(xiàn)在使用的HC都是PCI設(shè)備,乖乖,心中恍然大悟,有關(guān)PCI暫且不表,因為我暫時也不會,看官現(xiàn)在只要知道USB的HC都是PCI設(shè)備即可。 ehci_hcd_init的使命 位置:kernels/linux-2.6.32.21/drivers/usb/host walfred@ubuntu:~/work/kernels/linux-2.6.32.21/drivers/usb/host$ vim ehci-hcd.c static int __init ehci_hcd_init(void) { int retval = 0;
if (usb_disabled()) return -ENODEV;
printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) printk(KERN_WARNING "Warning! ehci_hcd should always be loaded" " before uhci_hcd and ohci_hcd, not after\n");
pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", hcd_name, sizeof(struct ehci_qh), sizeof(struct ehci_qtd), sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
#ifdef DEBUG ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root); if (!ehci_debug_root) { retval = -ENOENT; goto err_debug; } #endif
#ifdef PLATFORM_DRIVER retval = platform_driver_register(&PLATFORM_DRIVER); if (retval < 0) goto clean0; #endif
#ifdef PCI_DRIVER retval = pci_register_driver(&PCI_DRIVER); if (retval < 0) goto clean1; #endif
#ifdef PS3_SYSTEM_BUS_DRIVER retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER); if (retval < 0) goto clean2; #endif
#ifdef OF_PLATFORM_DRIVER retval = of_register_platform_driver(&OF_PLATFORM_DRIVER); if (retval < 0) goto clean3; #endif return retval;
#ifdef OF_PLATFORM_DRIVER /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */ clean3: #endif #ifdef PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); clean2: #endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); clean1: #endif #ifdef PLATFORM_DRIVER platform_driver_unregister(&PLATFORM_DRIVER); clean0: #endif #ifdef DEBUG debugfs_remove(ehci_debug_root); ehci_debug_root = NULL; err_debug: #endif clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); return retval; } module_init(ehci_hcd_init);
從模塊的入口函數(shù)看,ehci_hcd_init的主要作用就是向各平臺注冊echi控制器驅(qū)動,比如PLATFORM_DRIVER,PCI_DRIVER,PS3_SYSTEM_BUS_DRIVER,OF_PLATFORM_DRIVER等等,這邊我們主要看看向pci總線注冊驅(qū)動的PCI_DRIVER。這邊的PCI_DRIVER是一個宏,跟著代碼走!
#define PCI_DRIVER ehci_pci_driver
/* pci driver glue; this is a "new style" PCI driver module */ static struct pci_driver ehci_pci_driver = { .name = (char *) hcd_name, .id_table = pci_ids,
.probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, .shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM_SLEEP .driver = { .pm = &usb_hcd_pci_pm_ops }, #endif }; 既然分析的是PCI這一塊,我們看看代碼怎么走的 #ifdef PCI_DRIVER retval = pci_register_driver(&PCI_DRIVER); if (retval < 0) goto clean1; #endif 在上面函數(shù)中調(diào)用了,這么一個函數(shù),用source insight找到其 #define pci_register_driver(driver) \ __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) 看看這個帶參宏,調(diào)用的是__pci_register_driver,接著找啊找,游阿游 /** * __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;
spin_lock_init(&drv->dynids.lock); INIT_LIST_HEAD(&drv->dynids.list);
/* register with core */ error = driver_register(&drv->driver); if (error) goto out;
error = pci_create_newid_file(drv); if (error) goto out_newid;
error = pci_create_removeid_file(drv); if (error) goto out_removeid; out: return error;
out_removeid: pci_remove_newid_file(drv); out_newid: driver_unregister(&drv->driver); goto out; }
追尋著一系類的函數(shù),我們終于找到了我們的母親,error = driver_register(&drv->driver);就這下輕輕一調(diào),我們才把知道了在ehci_hcd_init完成的使命是注冊主控驅(qū)動。
USB子系統(tǒng)學(xué)習(xí)之EHCI(pci_bus_type兩個重量級函數(shù))設(shè)備驅(qū)動和設(shè)備是怎么相遇的呢? 那就順便分析下 drv->driver.bus = &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, .bus_attrs = pci_bus_attrs, .pm = PCI_PM_OPS_PTR, }; 其中有個bus的專用的,pci_bus_match函數(shù),這是linux設(shè)備模型中,bus所獨有的,我們也看下 /** * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure * @dev: the PCI device structure to match against * @drv: the device driver to search for matching PCI device id structures * * Used by a driver to check whether a PCI device present in the * system is in its list of supported devices. Returns the matching * pci_device_id structure or %NULL if there is no 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); if (found_id) return 1;
return 0; } 這個函數(shù)是條用了你一個比較NB的函數(shù),對,曾經(jīng)是宏,現(xiàn)在是函數(shù)的container_of,這里調(diào)用就是能夠從設(shè)備鏈表中找到這個pci的dev。 而其中pci_match_device()函數(shù)則就起到了媒婆的作用,這個函數(shù)做了什么事情呢?怎么讓驅(qū)動在茫茫設(shè)備海中找到這個獨一無二的EHCI呢? 事實的真相是這樣的: /** * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure * @drv: the PCI driver to match against * @dev: the PCI device structure to match against * * Used by a driver to check whether a PCI device present in the * system is in its list of supported devices. Returns the matching * pci_device_id structure or %NULL if there is no match. */ 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); } 這個函數(shù)所用做的就是分別在driver->dynid,driver->id_table這兩個列表(由一系列的pci_device_id構(gòu)成)里面查找,找到則返回這個設(shè)備的pci_device_id。(不妨比較一下pci_bus_type->match 和 usb_bus_type->match) struct pci_device_id { __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ kernel_ulong_t driver_data; /* Data private to the driver */ }; 注意,pci_device_id->driver_data 指向了每個 pci 設(shè)備驅(qū)動所特有的數(shù)據(jù)結(jié)構(gòu),比如 ehci 來說:.driver_data = (unsigned long) &ehci_pci_hc_driver。 而pci_device_probe()的行程呢? pci_device_probe() ---> __pci_device_probe() ---> pci_call_probe() ---> ( pci_driver->probe() )而ehci_pci_driver->probe = usb_hcd_pci_probe()。 所以說設(shè)備模型中總線也有probe函數(shù)的目的,是最終調(diào)用驅(qū)動的probe函數(shù)。記不得了總線模型的,可以回看: 所以現(xiàn)在很多電影都是搞倒序,最后再回到一開始的地方,總感覺這些導(dǎo)演上輩子曾是程序員,看代碼看多了,那么我們還是回到大導(dǎo)演們曾經(jīng)看過的代碼的開始處吧! int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct hc_driver *driver; struct usb_hcd *hcd; int retval;
if (usb_disabled()) return -ENODEV;
if (!id) return -EINVAL; driver = (struct hc_driver *)id->driver_data; if (!driver) return -EINVAL;
if (pci_enable_device(dev) < 0) return -ENODEV; dev->current_state = PCI_D0;
if (!dev->irq) { dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); retval = -ENODEV; goto err1; }
hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); if (!hcd) { retval = -ENOMEM; goto err1; }
if (driver->flags & HCD_MEMORY) { /* EHCI, OHCI */ hcd->rsrc_start = pci_resource_start(dev, 0); hcd->rsrc_len = pci_resource_len(dev, 0); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { dev_dbg(&dev->dev, "controller already in use\n"); retval = -EBUSY; goto err2; } hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { dev_dbg(&dev->dev, "error mapping memory\n"); retval = -EFAULT; goto err3; }
} else { /* UHCI */ int region;
for (region = 0; region < PCI_ROM_RESOURCE; region++) { if (!(pci_resource_flags(dev, region) & IORESOURCE_IO)) continue;
hcd->rsrc_start = pci_resource_start(dev, region); hcd->rsrc_len = pci_resource_len(dev, region); if (request_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) break; } if (region == PCI_ROM_RESOURCE) { dev_dbg(&dev->dev, "no i/o regions available\n"); retval = -EBUSY; goto err2; } }
pci_set_master(dev);
retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err4; set_hs_companion(dev, hcd); return retval;
err4: if (driver->flags & HCD_MEMORY) { iounmap(hcd->regs); err3: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); } else release_region(hcd->rsrc_start, hcd->rsrc_len); err2: clear_hs_companion(dev, hcd); usb_put_hcd(hcd); err1: pci_disable_device(dev); dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); return retval; } 下一節(jié)將重點分析這個probe函數(shù)! USB子系統(tǒng)學(xué)習(xí)之EHCI(pci_bus_type兩個重量級函數(shù))上一篇文章,說到了EHCI的使命,本該繼續(xù)usb_hcd_pci_probe的,但是在討論usb_hcd_pci_probe之前呢,需要理下未來會在usb_hcd_pci_probe中遇到的結(jié)構(gòu)體。 現(xiàn)看先下面這張數(shù)個結(jié)構(gòu)體纏綿的圖吧,圖像生動,但是截止目前還是不太好理解的,看完圖,喝口茶,看看下面的分析對你能不能起點作用。 難纏的結(jié)構(gòu)體,不過C語言就是這樣組織的 1.struct pci_driver ehci_pci_driver 還記得在ehci_hcd_init中注冊PCI_DRIVER嗎,記不得的話記得大明湖畔的PCI_DRIVER也行: 記不得可以翻看下retval = pci_register_driver(&PCI_DRIVER); 該PCI_DRIVER是一個宏 #define PCI_DRIVER ehci_pci_driver 所以我們需要找到ehci_pci_driver static struct pci_driver ehci_pci_driver = { .name = (char *) hcd_name,//static const char hcd_name [] = "ehci_hcd"; .id_table = pci_ids, .probe = usb_hcd_pci_probe, .remove = usb_hcd_pci_remove, .shutdown = usb_hcd_pci_shutdown, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &usb_hcd_pci_pm_ops }, #endif }; 這里面的pci_ids,就會是將來usb_hcd_pci_probe中的第二個參數(shù),我們上一篇中講過PCI總線的probe最后會調(diào)用usb_hcd_pci_probe的,上面的向總線注冊ehci_pci_driver,最后還是還回來了。 2.看下pci_ids: static const struct pci_device_id pci_ids [] = { { /* handle any USB 2.0 EHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0), .driver_data = (unsigned long) &ehci_pci_hc_driver, }, { /* end: all zeroes */ } }; 3.static const struct hc_driver ehci_pci_hc_driver 確切的說會用到pci_ids中的ehci_pci_hc_driver,那我們再把ehci_pci_hc_driver提出來看看: static const struct hc_driver ehci_pci_hc_driver = { .description = hcd_name, .product_desc = "EHCI Host Controller", .hcd_priv_size = sizeof(struct ehci_hcd), /* * generic hardware linkage */ .irq = ehci_irq, .flags = HCD_MEMORY | HCD_USB2, /* * basic lifecycle operations */ .reset = ehci_pci_setup, .start = ehci_run, #ifdef CONFIG_PM .pci_suspend = ehci_pci_suspend, .pci_resume = ehci_pci_resume, #endif .stop = ehci_stop, .shutdown = ehci_shutdown, /* * managing i/o requests and associated device resources */ .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, .endpoint_disable = ehci_endpoint_disable, .endpoint_reset = ehci_endpoint_reset, /* * scheduling support */ .get_frame_number = ehci_get_frame, /* * root hub support */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; /*-------------------------------------------------------------------------*/ /* PCI driver selection metadata; PCI hotplugging uses this */ static const struct pci_device_id pci_ids [] = { { /* handle any USB 2.0 EHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0), .driver_data = (unsigned long) &ehci_pci_hc_driver, }, { /* end: all zeroes */ } }; 可以看到這個結(jié)構(gòu)個頭不小,似乎有點意思,看這個我就知道了.product_desc = "EHCI Host Controller",它實際上就是EHCI的驅(qū)動,之前提到過EHCI是一個PCI設(shè)備,所以它應(yīng)該包含了PCI用來控制其操作的函數(shù),比如開啟(start),關(guān)閉(stop),重啟(reset),中斷的函數(shù),另外還看到了和urb相關(guān)的操作,這個urb可是USB通信的核心結(jié)構(gòu)體,暫且不表,以后會詳解。 在usb_hcd_pci_probe函數(shù)用到結(jié)構(gòu)體基本就是這些了,但是。。。 struct usb_hcd會提意見了,這坨結(jié)構(gòu)體的老大還沒有登場昵。這個講的很好,可以參閱。 |
|