一、导读
本文将描述linux-usb子系统的核心,主要分析其核心的初始化流程,文中源码基于内核版本:4.1.15。
linux usb子系统框架的核心位于/drivers/usb/core/目录中,文件结构如下图所示:
目录中各文件功能大致如下:
二、USB核心的初始化
在linux内核的启动阶段USB模块最早输出日志信息如下:
(1)[0.475284]usbcore:registerednewinterfacedriverusbfs (2)[0.475348]usbcore:registerednewinterfacedriverhub (3)[0.475400]usbcore:registerednewdevicedriverusb
从上述输出日志可知:第(1)行表示成功注册USB文件系统,且在系统正常启动后,会生成对应的/sys/bus/usb/目录。第(2)行表示成功注册USB HUB驱动。第(3)行表明成功注册USB通用设备驱动,即usb_generic_driver。通常USB设备都是以设备的身份先与usb_generic_driver匹配,匹配成功后,会分裂出接口,当对接口调用 device_add()后,会触发USB接口和USB驱动的匹配。
USB核心由/drivers/usb/core/usb.c文件描述。该文件以linux内核模块的方式设计,使用subsys_initcall(usb_init);将usb核心模块导出。其中,usb核心的初始化由usb_init()完成,实现如下:
staticint__initusb_init(void) { intretval; if(usb_disabled()){ pr_info("%s:USBsupportdisabled ",usbcore_name); return0; } usb_init_pool_max();//初始化pool_max参数 usb_debugfs_init();//初始化usb的调试文件系统debugfs usb_acpi_register();//初始化acpi retval=bus_register(&usb_bus_type);//向linux内核注册usb总线类型 if(retval) gotobus_register_failed; //注册usb通知器 retval=bus_register_notifier(&usb_bus_type,&usb_bus_nb); if(retval) gotobus_notifier_failed; //usb设备号初始化 retval=usb_major_init(); if(retval) gotomajor_init_failed; //注册usbfs驱动程序 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; //注册通用usb设备驱动 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()中执行了如下操作:
(1)判断linux内核是否开启了对USB的支持,如果不支持则直接返回。
(2)初始化调试文件系统关于usb的目录和文件:
staticintusb_debugfs_init(void) { //创建usb目录 usb_debug_root=debugfs_create_dir("usb",NULL); if(!usb_debug_root) return-ENOENT; //在usb目录下创建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相关的参数:
(4)向linux内核注册usb总线类型,usb总线类型定义如下:
structbus_typeusb_bus_type={ .name="usb", .match=usb_device_match, .uevent=usb_uevent, };
(5)注册usb总线通知器
(6)初始化usb主设备号:
intusb_major_init(void) { interror; //注册usb字符设备 error=register_chrdev(USB_MAJOR,"usb",&usb_fops); if(error) printk(KERN_ERR"Unabletogetmajor%dforusbdevices ", USB_MAJOR); returnerror; }
(7)注册usbfs驱动程序,usbfs以usb驱动程序的形式进行定义:
structusb_driverusbfs_driver={ .name="usbfs", .probe=driver_probe, .disconnect=driver_disconnect, .suspend=driver_suspend, .resume=driver_resume, };
(8)初始化usb的devio,实质上是初始化USB字符设备,devio用于USB设备与用户空间进行通信:
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; } //注册usbdev_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驱动方式进行设计(/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)注册通用usb设备驱动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启动过程中或者是在插入USB设备后,通常USB设备都是以设备的身份先与usb_generic_driver匹配,这时候由.probe指向的generic_peobe()会执行,当匹配成功后,会分裂出接口,当对接口调用device_add()后,会触发USB接口和USB接口驱动的匹配。
generic_probe()函数实现如下:
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){ //设置配置 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设备添加,对应注册的回调函数会被执行。 return0; }
三、总结
本文主要描述linux-usb核心的初始化,usb核心是usb子系统的内层,其他的usb模块都基于这个内层再设计。除此之外,着重描述了usb_init()函数的具体执行步骤,如下图所示:
审核编辑:刘清
-
USB接口
+关注
关注
9文章
699浏览量
55572 -
ACPI
+关注
关注
1文章
11浏览量
8948 -
LINUX内核
+关注
关注
1文章
316浏览量
21617
原文标题:Linux-USB驱动框架 | usb核心
文章出处:【微信号:嵌入式小生,微信公众号:嵌入式小生】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论