寫一下UHCI吧,也順便懷念一下Intel,以及Intel的那幾個女同事們,好久沒聯絡了,你們可好?
UHCI是Intel提出來的.雖然離開Intel一年多了,但我總覺得也許有一天我還會回到Intel.所以關於Intel的東西,我多少會關注一下.我挺懷念Intel的,雖然錢也不多,但是那時候畢竟剛畢業,對錢的問題也沒想太多.
UHCI全名Universal Host Controller Interface,它是一種USB主機控制器的介面規範,江湖中把遵守它的硬體稱為UHCI主機控制器.在Linux中,把這種硬體叫做HC,或者說Host Controller,而把與它對應的軟體叫做HCD.即HC Driver.Linux中這個HCD所對應的模組叫做uhci-hcd.
當我們看一個模組的時候,首先是看Kconfig和Makefile檔案.在drivers/usb/host/Kconfig檔案中:
161 config USB_UHCI_HCD
162 tristate "UHCI HCD (most Intel and VIA) support"
163 depends on USB && PCI
164 ---help---
165 The Universal Host Controller Interface is a standard by Intel for
166 accessing the USB hardware in the PC (which is also called the USB
167 host controller). If your USB host controller conforms to this
168 standard, you may want to say Y, but see below. All recent boards
169 with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX,
170 i810, i820) conform to this standard. Also all VIA PCI chipsets
171 (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro
172 133). If unsure, say Y.
173
174 To compile this driver as a module, choose M here: the
175 module will be called uhci-hcd.
眾裡尋他千百度之後,我發現了上面這段文字,注意那句depends on USB && PCI.這句話的意思就是說這個選項是依賴於另外兩個選項,CONFIG_USB和CONFIG_PCI,很顯然這兩個選項代表著Linux中usb的核心代碼和pci的核心代碼.
UHCI作為USB主機控制器的介面,它依賴於usb核心這很正常,但為何它也依賴於pci核心呢?理由很簡單,UHCI主機控制器本身通常是PCI裝置,即通常它會插在PCI插槽裡,或者直接就整合在主板上.但總之,大多數的UHCI主機控制器是連在PCI匯流排上的.所以,很無奈的是,寫UHCI驅動程式就不得不瞭解一點PCI裝置驅動程式.
先用lspci命令看一下,
localhost:/usr/src/linux-2.6.22.1/drivers/usb/host # lspci | grep USB
00:1d.0 USB Controller: Intel Corporation Enterprise Southbridge UHCI USB #1 (rev 09)
00:1d.1 USB Controller: Intel Corporation Enterprise Southbridge UHCI USB #2 (rev 09)
00:1d.2 USB Controller: Intel Corporation Enterprise Southbridge UHCI USB #3 (rev 09)
00:1d.7 USB Controller: Intel Corporation Enterprise Southbridge EHCI USB (rev 09)
比如在我的電腦裡,就有三個UHCI主機控制器,以及另一個主機控制器,EHCI主機控制器,它們都是pci裝置.
接著我們來看Makefile.
localhost:/usr/src/linux-2.6.22.1/drivers/usb/host # cat Makefile
#
# Makefile for USB Host Controller Drivers
#
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
很顯然,我們要的就是與CONFIG_USB_UHCI_HCD對應的uhci-hcd.o這個模組.而與uhci-hcd.o最相關的就是與之同名的C檔案.這是它的源檔案.在drivers/usb/host/uhci-hcd.c的最後7行,我們看到:
969 module_init(uhci_hcd_init);
970 module_exit(uhci_hcd_cleanup);
971
972 MODULE_AUTHOR(DRIVER_AUTHOR);
973 MODULE_DESCRIPTION(DRIVER_DESC);
974 MODULE_LICENSE("GPL");
正如每個女人都應該有一支口紅,每個模組都應該有兩個宏,它們是module_init和module_exit,分別用來初始化和登出自己.而這兩行代碼的意思就是說uhci_hcd_init這個函數將會在你載入這個模組的時候被調用,uhci_hcd_cleanup則是將會在你卸載這個模組的時候被執行.
所以我們沒有辦法,只能從uhci_hcd_init開始我們的故事.
917 static int __init uhci_hcd_init(void)
918 {
919 int retval = -ENOMEM;
920
921 printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION "%s/n",
922 ignore_oc ? ", overcurrent ignored" : "");
923
924 if (usb_disabled())
925 return -ENODEV;
926
927 if (DEBUG_CONFIGURED) {
928 errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
929 if (!errbuf)
930 goto errbuf_failed;
931 uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
932 if (!uhci_debugfs_root)
933 goto debug_failed;
934 }
935
936 uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
937 sizeof(struct urb_priv), 0, 0, NULL, NULL);
938 if (!uhci_up_cachep)
939 goto up_failed;
940
941 retval = pci_register_driver(&uhci_pci_driver);
942 if (retval)
943 goto init_failed;
944
945 return 0;
946
947 init_failed:
948 kmem_cache_destroy(uhci_up_cachep);