linux usb 子系統(二)- host driver
- 瞭解usb host driver.
1.USB Subsystem Framework
The following chart shows the framework of the USB subsystem in Linux. Like i2c, the USB subsystem can be divided into three layers: ** Device Driver Layer - USB Core - Controller Driver Layer*
The usb protocol is a complex protocol,The currently involved versions are usb1.0, usb2.0, usb3.0. If you open the kernel usb host directory, you will find that the following contains various forms of controller drivers such as ohci, uhci, ehci, xhci, and whci.
2.USB core 初始化
usb_int 初始化整個usb系統的基礎部分。(drivers/usb/core/usb.c)
865 static int __init usb_init(void)
866 {
867 int retval;
868 if (nousb) {
869 pr_info("%s: USB support disabled/n", usbcore_name);
870 return 0;
871 }
872
873 retval = ksuspend_usb_init();
874 if (retval)
875 goto out;
876 retval = bus_register(&usb_bus_type);
877 if (retval)
878 goto bus_register_failed;
879 retval = usb_host_init();
880 if (retval)
881 goto host_init_failed;
882 retval = usb_major_init();
883 if (retval)
884 goto major_init_failed;
885 retval = usb_register(&usbfs_driver);
886 if (retval)
887 goto driver_register_failed;
888 retval = usb_devio_init();
889 if (retval)
890 goto usb_devio_init_failed;
891 retval = usbfs_init();
892 if (retval)
893 goto fs_init_failed;
894 retval = usb_hub_init();
895 if (retval)
896 goto hub_init_failed;
897 retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
898 if (!retval)
899 goto out;
900
901 usb_hub_cleanup();
902 hub_init_failed:
903 usbfs_cleanup();
904 fs_init_failed:
905 usb_devio_cleanup();
906 usb_devio_init_failed:
907 usb_deregister(&usbfs_driver);
908 driver_register_failed:
909 usb_major_cleanup();
910 major_init_failed:
911 usb_host_cleanup();
912 host_init_failed:
913 bus_unregister(&usb_bus_type);
914 bus_register_failed:
915 ksuspend_usb_cleanup();
916 out:
917 return retval;
918 }
- 註冊USB匯流排
bus_register(&usb_bus_type); - 註冊usbfs驅動
usb_register(&usbfs_driver); - 註冊usb hub驅動
usb_hub_init -> usb_register(&hub_driver) - 註冊通用裝置驅動
usb_register_device_driver(&usb_generic_driver, THIS_MODULE)
3.s3c2410 host driver
3.1.Makefile:
obj-$(config_usb_ohci_hcd_s3c2410) +=ohci-s3c2410.o
obj-$(config_usb_ohci_hcd) +=ohci-hcd.o
3.2.Kconfig
config usb_ohci_hcd_s3c2410
tristate "ohci support for samsung s3c24xx/s3c64xx soc series"
depends on usb_ohci_hcd&&(arch_s3c24xx || arch_s3c64xx)
default y
--- help ---
enables support for the on-chip ohci controller on
s3c24xx/s3c64xx chips.
config usb_ohci_hcd
tristate "ohci hcd (usb 1.1) support"
depends on has_dma && has_iomem
3.3.files
- drivers/usb/host/ohci-hcd.c
- ohci-s3c2410.c
4.程式碼分析
drivers/usb/host/ohci-s3c2410.c :
468 static int __init ohci_s3c2410_init(void)
469 {
470 if (usb_disabled())
471 return -ENODEV;
472
473 pr_info("%s: " DRIVER_DESC "\n", hcd_name);
474 ohci_init_driver(&ohci_s3c2410_hc_driver, NULL);
475
476 /*
477 * The Samsung HW has some unusual quirks, which require
478 * Sumsung-specific workarounds. We override certain hc_driver
479 * functions here to achieve that. We explicitly do not enhance
480 * ohci_driver_overrides to allow this more easily, since this
481 * is an unusual case, and we don't want to encourage others to
482 * override these functions by making it too easy.
483 */
484
485 ohci_s3c2410_hc_driver.hub_status_data = ohci_s3c2410_hub_status_data;
486 ohci_s3c2410_hc_driver.hub_control = ohci_s3c2410_hub_control;
487
488 return platform_driver_register(&ohci_hcd_s3c2410_driver);
489 }
490 module_init(ohci_s3c2410_init);
ohci_hcd_s3c2410_driver作為platform_driver例項,指定當與bus上相應的platform_device匹配後需要執行的probe函式。ohci的platform_device在arch/arm/plat-samsumg/devs.c中定義:
939 struct platform_device s3c_device_ohci = {
940 .name = "s3c2410-ohci",
941 .id = -1,
942 .num_resources = ARRAY_SIZE(s3c_usb_resource),
943 .resource = s3c_usb_resource,
944 .dev = {
945 .dma_mask = &samsung_device_dma_mask,
946 .coherent_dma_mask = DMA_BIT_MASK(32),
947 }
948 };
bus_match成功後,執行ohci_hcd_s3c2410_probe函式進行驅動的載入。
static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,
struct platform_device *dev)
{
struct usb_hcd *hcd = NULL;
struct s3c2410_hcd_info *info = dev_get_platdata(&dev->dev);
int retval;
s3c2410_usb_set_power(info, 1, 1);
s3c2410_usb_set_power(info, 2, 1);
hcd = usb_create_hcd(driver, &dev->dev, "s3c24xx");
if (hcd == NULL)
return -ENOMEM;
hcd->rsrc_start = dev->resource[0].start; // 指向hc 的暫存器首地址0x49000000
hcd->rsrc_len = resource_size(&dev->resource[0]);
hcd->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]); // 轉換為虛擬地址
clk = devm_clk_get(&dev->dev, "usb-host");
usb_clk = devm_clk_get(&dev->dev, "usb-bus-host");
s3c2410_start_hc(dev, hcd);
retval = usb_add_hcd(hcd, dev->resource[1].start, 0); //中斷號26
device_wakeup_enable(hcd->self.controller);
return 0;
err_ioremap:
s3c2410_stop_hc(dev);
err_put:
usb_put_hcd(hcd);
return retval;
}
4.1.usb_create_hcd
struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
struct device *dev, char *bus_name)
{
struct usb_hcd *hcd;
//申請空間,hcd_priv_size為動態的附加結構長度, 附加在usb_hcd的尾部
// 這段空間用於主機控制器的私有結構,uhci的私有結構為uhci_hcd,用於描述uhci的屬性
hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
if (!hcd)
{
dev_dbg (dev, "hcd alloc failed\n");
return NULL;
}
//連線usb_hcd到pci_device
dev_set_drvdata(dev, hcd);
//初始化引用計數器
kref_init(&hcd->kref);
//初始化usb匯流排
usb_bus_init(&hcd->self);
//連線pci_device到usb_hcd的usb_bus上
hcd->self.controller = dev;
//設定usb_bus名稱
hcd->self.bus_name = bus_name;
//設定是否使用dma
hcd->self.uses_dma = (dev->dma_mask != NULL);
//hcd->rh_timer的註釋為drives root-hub polling
//字面意思是一個用於記時執行某函式的結構,例如5ms後執行指定函式
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_PM
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
//連線hc_driver到usb_hcd上
hcd->driver = driver;
//設定裝置名稱
hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller";
return hcd;
}
rh_timer_func這個是root_hub輪詢計時器 ,控制器以輪詢的方式查詢埠變化狀態。 rh_timer_func呼叫usb_hcd_poll_rh_status,呼叫流程:
->usb_hcd_poll_rh_status //hcd.c
->hcd->driver->hub_status_data(hcd, buffer)
->usb_hcd_unlink_urb_from_ep(hcd, urb);
->usb_hcd_giveback_urb(hcd, urb, 0)
->usb_giveback_urb_bh(); //tasklet_hi_schedule(&bh->bh);
->__usb_hcd_giveback_urb(urb);
->urb->complete(urb); //hub_irq
->hub_irq //hub.c usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
->kick_hub_wq(hub);
->hub_event //INIT_WORK(&hub->events, hub_event);
->port_event(hub, i);
->hub_port_connect_change
->hub_port_connect
->hub_port_init
->usb_new_device(udev);
->usb_enumerate_device(udev);//開始列舉
->device_add(&udev->dev);//列舉完畢後載入裝置驅動
device_add函式會出發匯流排的通知鏈傳送通知,最終會呼叫匯流排的match方法。usb裝置和驅動一旦match,則會呼叫驅動的drvwrap.driver.probe方法:
- 若是裝置則通過driver.c的usb_register_device_driver函式呼叫usb_probe_device方法
- 若是介面則通過driver.c的usb_register_driver函式呼叫usb_probe_interface方法
- 假設是U盤接入,則呼叫mass_storage驅動的probe,並在probe中使用usb_alloc_urb分配urb,最後usb_submit_urb提交urb。
4.2.usb_add_hcd 新增hcd到系統中
-
向usb系統中註冊一條匯流排
usb_register_bus(&hcd->self)) -
建立一個USB裝置,作為根hub
rhdev = usb_alloc_dev(NULL, &hcd->self, 0)
hcd->self.root_hub = rhdev -
申請中斷並註冊中斷函式usb_hub_irq
usb_hcd_request_irqs -
為該匯流排註冊根hub
register_root_hub(hcd)- 獲取根hub的描述資訊
usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE); - 向usb系統中新增了一個usb裝置
usb_new_device (usb_dev);
- 獲取根hub的描述資訊
相關文章
- garmin USB: linux USB host驅動Linux
- 驅動Driver-input子系統
- Choosing a driver model for developing a USB client driverdevclient
- 驅動Driver-Pinctrl-GPIO子系統
- android USB host程式設計Android程式設計
- Android Qcom USB Driver學習(零)Android
- Android Qcom USB Driver學習(十四)Android
- linux系統中 SElinux安全子系統Linux
- Linux中斷子系統Linux
- 【原創】Linux中斷子系統(二)-通用框架處理Linux框架
- Linux驅動之GPIO子系統和pinctrl子系統Linux
- Linux ubi子系統原理分析Linux
- linux時間子系統(三)Linux
- Windows linux子系統 使用說明WindowsLinux
- Linux Media 子系統鏈路分析Linux
- Windows10系統如何重置/登出Linux子系統WindowsLinux
- Linux系統管理命令二(轉)Linux
- SciTech-OS-Linux-Device Driver: 英文原版電子書“Linux Device Drivers, Third Edition”Linuxdev
- I2C子系統框架二框架
- 嵌入式Linux—輸入子系統Linux
- Arm-Linux子系統的互相NotifyLinux
- 【linux】驅動-11-gpio子系統Linux
- 【linux】驅動-10-pinctrl子系統Linux
- Linux 筆記分享二:Linux 系統安裝Linux筆記
- 二、Linux檔案系統結構Linux
- 電子公文傳輸系統-進展二
- xshell登陸Win10Linux子系統Win10Linux
- windows11 如何開啟linux子系統WindowsLinux
- 啟用 Win10 的 Linux 子系統Win10Linux
- Window10安裝linux子系統及子系統安裝1Panel皮膚Linux
- Win10系統訪問Linux子系統檔案的方法Win10Linux
- 二、Linux系統安裝和基本使用Linux
- JVM第二篇-類載入子系統JVM
- 初探pinctrl子系統和GPIO子系統
- Win10系統怎麼匯出或匯入Linux子系統Win10Linux
- WSL2:Windows 親生的 Linux 子系統WindowsLinux
- Mac開發安卓時,SDK Tools下找不到Google Usb DriverMac安卓Go
- gpio子系統與pinctrl子系統通用APIAPI