一、導(dǎo)讀
本文將描述linux-usb子系統(tǒng)的核心,主要分析其核心的初始化流程,文中源碼基于內(nèi)核版本:4.1.15。
linux usb子系統(tǒng)框架的核心位于/drivers/usb/core/目錄中,文件結(jié)構(gòu)如下圖所示:
目錄中各文件功能大致如下:
二、USB核心的初始化
在linux內(nèi)核的啟動(dòng)階段USB模塊最早輸出日志信息如下:
(1)[0.475284]usbcore:registerednewinterfacedriverusbfs (2)[0.475348]usbcore:registerednewinterfacedriverhub (3)[0.475400]usbcore:registerednewdevicedriverusb
從上述輸出日志可知:第(1)行表示成功注冊(cè)USB文件系統(tǒng),且在系統(tǒng)正常啟動(dòng)后,會(huì)生成對(duì)應(yīng)的/sys/bus/usb/目錄。第(2)行表示成功注冊(cè)USB HUB驅(qū)動(dòng)。第(3)行表明成功注冊(cè)USB通用設(shè)備驅(qū)動(dòng),即usb_generic_driver。通常USB設(shè)備都是以設(shè)備的身份先與usb_generic_driver匹配,匹配成功后,會(huì)分裂出接口,當(dāng)對(duì)接口調(diào)用 device_add()后,會(huì)觸發(fā)USB接口和USB驅(qū)動(dòng)的匹配。
USB核心由/drivers/usb/core/usb.c文件描述。該文件以linux內(nèi)核模塊的方式設(shè)計(jì),使用subsys_initcall(usb_init);將usb核心模塊導(dǎo)出。其中,usb核心的初始化由usb_init()完成,實(shí)現(xiàn)如下:
staticint__initusb_init(void) { intretval; if(usb_disabled()){ pr_info("%s:USBsupportdisabled ",usbcore_name); return0; } usb_init_pool_max();//初始化pool_max參數(shù) usb_debugfs_init();//初始化usb的調(diào)試文件系統(tǒng)debugfs usb_acpi_register();//初始化acpi retval=bus_register(&usb_bus_type);//向linux內(nèi)核注冊(cè)u(píng)sb總線類型 if(retval) gotobus_register_failed; //注冊(cè)u(píng)sb通知器 retval=bus_register_notifier(&usb_bus_type,&usb_bus_nb); if(retval) gotobus_notifier_failed; //usb設(shè)備號(hào)初始化 retval=usb_major_init(); if(retval) gotomajor_init_failed; //注冊(cè)u(píng)sbfs驅(qū)動(dòng)程序 retval=usb_register(&usbfs_driver); if(retval) gotodriver_register_failed; //初始化usb的devio retval=usb_devio_init(); if(retval) gotousb_devio_init_failed; //初始化usb的hub retval=usb_hub_init(); if(retval) gotohub_init_failed; //注冊(cè)通用usb設(shè)備驅(qū)動(dòng) retval=usb_register_device_driver(&usb_generic_driver,THIS_MODULE); if(!retval) gotoout; usb_hub_cleanup(); hub_init_failed: usb_devio_cleanup(); usb_devio_init_failed: usb_deregister(&usbfs_driver); driver_register_failed: usb_major_cleanup(); major_init_failed: bus_unregister_notifier(&usb_bus_type,&usb_bus_nb); bus_notifier_failed: bus_unregister(&usb_bus_type); bus_register_failed: usb_acpi_unregister(); usb_debugfs_cleanup(); out: returnretval; }
從上述代碼可見,usb_init()中執(zhí)行了如下操作:
(1)判斷l(xiāng)inux內(nèi)核是否開啟了對(duì)USB的支持,如果不支持則直接返回。
(2)初始化調(diào)試文件系統(tǒng)關(guān)于usb的目錄和文件:
staticintusb_debugfs_init(void) { //創(chuàng)建usb目錄 usb_debug_root=debugfs_create_dir("usb",NULL); if(!usb_debug_root) return-ENOENT; //在usb目錄下創(chuàng)建devices文件 usb_debug_devices=debugfs_create_file("devices",0444, usb_debug_root,NULL, &usbfs_devices_fops); if(!usb_debug_devices) { debugfs_remove(usb_debug_root); usb_debug_root=NULL; return-ENOENT; } return0; }
(3)初始化usb與acpi相關(guān)的參數(shù):
(4)向linux內(nèi)核注冊(cè)u(píng)sb總線類型,usb總線類型定義如下:
structbus_typeusb_bus_type={ .name="usb", .match=usb_device_match, .uevent=usb_uevent, };
(5)注冊(cè)u(píng)sb總線通知器
(6)初始化usb主設(shè)備號(hào):
intusb_major_init(void) { interror; //注冊(cè)u(píng)sb字符設(shè)備 error=register_chrdev(USB_MAJOR,"usb",&usb_fops); if(error) printk(KERN_ERR"Unabletogetmajor%dforusbdevices ", USB_MAJOR); returnerror; }
(7)注冊(cè)u(píng)sbfs驅(qū)動(dòng)程序,usbfs以u(píng)sb驅(qū)動(dòng)程序的形式進(jìn)行定義:
structusb_driverusbfs_driver={ .name="usbfs", .probe=driver_probe, .disconnect=driver_disconnect, .suspend=driver_suspend, .resume=driver_resume, };
(8)初始化usb的devio,實(shí)質(zhì)上是初始化USB字符設(shè)備,devio用于USB設(shè)備與用戶空間進(jìn)行通信:
int__initusb_devio_init(void) { intretval; retval=register_chrdev_region(USB_DEVICE_DEV,USB_DEVICE_MAX, "usb_device"); if(retval){ printk(KERN_ERR"Unabletoregisterminorsforusb_device "); gotoout; } cdev_init(&usb_device_cdev,&usbdev_file_operations); retval=cdev_add(&usb_device_cdev,USB_DEVICE_DEV,USB_DEVICE_MAX); if(retval){ printk(KERN_ERR"Unabletogetusb_devicemajor%d ", USB_DEVICE_MAJOR); gotoerror_cdev; } //注冊(cè)u(píng)sbdev_nb通知器 usb_register_notify(&usbdev_nb); out: returnretval; error_cdev: unregister_chrdev_region(USB_DEVICE_DEV,USB_DEVICE_MAX); gotoout; }
(9)初始化usb的hub,hub也是以USB驅(qū)動(dòng)方式進(jìn)行設(shè)計(jì)(/drivers/usb/core/hub.c):
staticstructusb_driverhub_driver={ .name="hub", .probe=hub_probe, .disconnect=hub_disconnect, .suspend=hub_suspend, .resume=hub_resume, .reset_resume=hub_reset_resume, .pre_reset=hub_pre_reset, .post_reset=hub_post_reset, .unlocked_ioctl=hub_ioctl, .id_table=hub_id_table, .supports_autosuspend=1, }; intusb_hub_init(void) { if(usb_register(&hub_driver)0)?{ ??printk(KERN_ERR?"%s:?can't?register?hub?driver ", ???usbcore_name); ??return?-1; ?} ?/* ??*?The?workqueue?needs?to?be?freezable?to?avoid?interfering?with ??*?USB-PERSIST?port?handover.?Otherwise?it?might?see?that?a?full-speed ??*?device?was?gone?before?the?EHCI?controller?had?handed?its?port ??*?over?to?the?companion?full-speed?controller. ??*/ ?hub_wq?=?alloc_workqueue("usb_hub_wq",?WQ_FREEZABLE,?0); ?if?(hub_wq) ??return?0; ?/*?Fall?through?if?kernel_thread?failed?*/ ?usb_deregister(&hub_driver); ?pr_err("%s:?can't?allocate?workqueue?for?usb?hub ",?usbcore_name); ?return?-1; }
(10)注冊(cè)通用usb設(shè)備驅(qū)動(dòng)usb_generic_driver,定義如下(/drivers/usb/core/generic.c):
structusb_device_driverusb_generic_driver={ .name="usb", .probe=generic_probe, .disconnect=generic_disconnect, #ifdefCONFIG_PM .suspend=generic_suspend, .resume=generic_resume, #endif .supports_autosuspend=1, };
?從前文描述可知:在linux啟動(dòng)過程中或者是在插入U(xiǎn)SB設(shè)備后,通常USB設(shè)備都是以設(shè)備的身份先與usb_generic_driver匹配,這時(shí)候由.probe指向的generic_peobe()會(huì)執(zhí)行,當(dāng)匹配成功后,會(huì)分裂出接口,當(dāng)對(duì)接口調(diào)用device_add()后,會(huì)觸發(fā)USB接口和USB接口驅(qū)動(dòng)的匹配。
generic_probe()函數(shù)實(shí)現(xiàn)如下:
staticintgeneric_probe(structusb_device*udev) { interr,c; /*Chooseandsettheconfiguration.Thisregisterstheinterfaces *withthedrivercoreandletsinterfacedriversbindtothem. */ if(udev->authorized==0) dev_err(&udev->dev,"Deviceisnotauthorizedforusage "); else{ //選擇配置 c=usb_choose_configuration(udev); if(c>=0){ //設(shè)置配置 err=usb_set_configuration(udev,c); if(err&&err!=-ENODEV){ dev_err(&udev->dev,"can'tsetconfig#%d,error%d ", c,err); /*Thisneednotbefatal.Theusercantryto *setotherconfigurations.*/ } } } /*USBdevicestate==configured...usable*/ usb_notify_add_device(udev);//通知usb設(shè)備添加,對(duì)應(yīng)注冊(cè)的回調(diào)函數(shù)會(huì)被執(zhí)行。 return0; }
三、總結(jié)
本文主要描述linux-usb核心的初始化,usb核心是usb子系統(tǒng)的內(nèi)層,其他的usb模塊都基于這個(gè)內(nèi)層再設(shè)計(jì)。除此之外,著重描述了usb_init()函數(shù)的具體執(zhí)行步驟,如下圖所示:
審核編輯:劉清
-
USB接口
+關(guān)注
關(guān)注
9文章
701瀏覽量
55634 -
ACPI
+關(guān)注
關(guān)注
1文章
11瀏覽量
8953 -
LINUX內(nèi)核
+關(guān)注
關(guān)注
1文章
316瀏覽量
21644
原文標(biāo)題:Linux-USB驅(qū)動(dòng)框架 | usb核心
文章出處:【微信號(hào):嵌入式小生,微信公眾號(hào):嵌入式小生】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論