0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

linux-usb子系统的核心描述

嵌入式小生 来源:嵌入式小生 2023-01-14 09:37 次阅读

一、导读

本文将描述linux-usb子系统的核心,主要分析其核心的初始化流程,文中源码基于内核版本:4.1.15。

linux usb子系统框架的核心位于/drivers/usb/core/目录中,文件结构如下图所示:

ad39d590-93a3-11ed-bfe3-dac502259ad0.png

目录中各文件功能大致如下:

ad63df16-93a3-11ed-bfe3-dac502259ad0.png

二、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相关的参数:

ad8a6500-93a3-11ed-bfe3-dac502259ad0.png

(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()函数的具体执行步骤,如下图所示:

ada72064-93a3-11ed-bfe3-dac502259ad0.jpg





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • USB接口
    +关注

    关注

    9

    文章

    699

    浏览量

    55572
  • ACPI
    +关注

    关注

    1

    文章

    11

    浏览量

    8948
  • LINUX内核
    +关注

    关注

    1

    文章

    316

    浏览量

    21617

原文标题:Linux-USB驱动框架 | usb核心

文章出处:【微信号:嵌入式小生,微信公众号:嵌入式小生】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于Linux设备驱动中input子系统的介绍

    对于输入类设备如键盘、鼠标、触摸屏之类的Linux驱动,内核提供input子系统,使得这类设备的处理变得非常便捷。总体上来讲,input子系统由三部分组成: 事件驱动input核心设备
    发表于 01-09 16:06 2685次阅读

    Linux下输入子系统上报触摸屏坐标

      在 Linux 中,输入子系统是由输入子系统设备驱动层、输入子系统核心层(Input Core)和输入
    的头像 发表于 09-25 08:56 2397次阅读
    <b class='flag-5'>Linux</b>下输入<b class='flag-5'>子系统</b>上报触摸屏坐标

    Linux LED子系统详解

    Linux LED子系统详解
    的头像 发表于 06-10 10:37 1517次阅读
    <b class='flag-5'>Linux</b> LED<b class='flag-5'>子系统</b>详解

    嵌入式技术:Linux驱动USB必须了解的四个描述

    module_init,只不过因为这部分代码是核心,开发者通常把它看作一个子系统,而不仅仅是一个模块。因为USB core模块代表的不是某一个设备,而是所有USB设备赖以生存的模块。因
    发表于 05-09 09:06

    输入子系统的作用与框架

    了一个底层驱动(成为serio)的集合,支持对串口和键盘控制器等硬件输入的访问  输入子系统使得应用编程人员和驱动编程人员编程的时候变得简单统一。3、输入子系统框架linux输入子系统
    发表于 10-19 17:13

    基于USB设备的Linux网络驱动程序开发

    介绍Linux 的体系结构及其网络子系统,并结合USB 设备在Linux 下的访问机制,给出了一种USB 网络驱动程序的设计方法。该设计方法
    发表于 08-11 11:23 20次下载

    基于Linux内核输入子系统的驱动研究

    Linux因其完全开放的特性和稳定优良的性能深受欢迎,当推出了内核输入子系统后,更方便了嵌入式领域的驱动开放。介绍了Linux的设备驱动基础,详细阐述了基于Linux内核输入
    发表于 09-12 16:38 23次下载

    Linux内核输入子系统的驱动研究

    Linux内核输入子系统的驱动研究
    发表于 10-31 14:41 14次下载
    <b class='flag-5'>Linux</b>内核输入<b class='flag-5'>子系统</b>的驱动研究

    Linux usb子系统子系统架构

    USB 分为主从两大体系,一般而言, PC 中的 USB 系统就是作主,而一般的 USB 鼠标, U 盘则是典型的 USB
    发表于 05-07 10:35 1312次阅读

    详细了解Linux设备模型中的input子系统

    linux输入子系统linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler)、输入
    发表于 05-12 09:04 1031次阅读
    详细了解<b class='flag-5'>Linux</b>设备模型中的input<b class='flag-5'>子系统</b>

    Windows 子系统助力 Linux 2.0

    Windows 子系统助力 Linux 2.0
    的头像 发表于 01-04 11:17 628次阅读

    从软件角度分析linux内核USB子系统的热插拔过程

    本文从软件角度分析linux内核USB子系统的热插拔过程,以实际分析思路和过程行文,基于linux内核版本:4.19.4,记录分析USB
    的头像 发表于 01-15 09:28 5418次阅读

    Linux中内存管理子系统开发必知的3个结构概念

    Linux中内存管理子系统使用节点(node)、区域(zone)和页(page)三级结构描述物理内存。
    的头像 发表于 08-28 09:34 860次阅读
    <b class='flag-5'>Linux</b>中内存管理<b class='flag-5'>子系统</b>开发必知的3个结构概念

    Linux内核之LED子系统(二)

    这里说一说LED子系统的一些核心源代码文件,是如何实现LED子系统
    发表于 10-02 16:55 835次阅读
    <b class='flag-5'>Linux</b>内核之LED<b class='flag-5'>子系统</b>(二)

    深度解析linux时钟子系统

    linux内核中实现了一个CLK子系统,用于对上层提供各模块(例如需要时钟信号的外设,USB等)的时钟驱动接口,对下层提供具体SOC的时钟操作细节。
    的头像 发表于 09-29 16:46 296次阅读
    深度解析<b class='flag-5'>linux</b>时钟<b class='flag-5'>子系统</b>