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

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

3天内不再提示

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

嵌入式小生 来源:嵌入式小生 2023-01-15 09:28 次阅读

本文从软件角度分析linux内核USB子系统的热插拔过程,以实际分析思路和过程行文,基于linux内核版本:4.19.4,记录分析USB子系统时的所得。

导读

一、USB核心初始化

二、USB设备的枚举过程

(2-1)USB鼠标插入后日志分析

(2-2)USB鼠标移除/拔下后日志分析

三、 USB host控制器的初始化

四、USB设备插入后的硬件过程

五、USB设备插入后的软件过程

一、USB核心初始化

如果linux内核开启了对USB的支持,在内核启动过程中,首先会对USB核心进行初始化,该过程则会打印出如下日志信息

(1)[ 0.476223] usbcore: registered new interface driver usbfs

(2)[ 0.476286] usbcore: registered new interface driver hub

(3)[ 0.476337] usbcore: registered new device driver usb

上述(1)、(2)两条信息是调用usb_register_driver()函数时打印出的,从而可以知道在linux内核启动过程中,usb核心会注册usbfs、hub接口驱动程序。从内核源码角度,以上hub接口驱动程序的注册过程是在usb_init()中调用usb_hub_init()完成的,除此之外还创建了hub_wq工作队列:

上述第(3)条信息是在usb_init()中调用:

usb_register_device_driver(&usb_generic_driver,THIS_MODULE);

当在成功注册usb设备驱动后打印出的日志信息。

二、USB设备的枚举过程

本小节以低速USB鼠标设备插入为例,查看linux内核对USB设备的枚举过程。

(2-1)USB鼠标插入后日志分析

我们都知道USB支持热插拔,在linux系统中,这个热插拔是怎样的一个过程,本小节将描述这个话题

当USB设备接入系统时(热插拔探测过程),文本以插入一个USB鼠标为例,则会打印出类似下述的信息:

[ 3122.476846] usb 4-1: new low-speed USB device number 5 using ohci-platform

[ 3122.702408] usb 4-1: New USB device found, idVendor=17ef, idProduct=6019, bcdDevice= 1.00

[ 3122.702503] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0

[ 3122.702537] usb 4-1: Product: Lenovo Optical USB Mouse

[ 3122.702568] usb 4-1: Manufacturer: PixArt

[ 3122.713317] input: PixArt Lenovo Optical USB Mouse as /devices/platform/fd8c0000.usb/usb4/4-1/4-1:1.0/00036019.0004/input/input8

[ 3122.771015] hid-generic 00036019.0004: input,hidraw0: USB HID v1.11 Mouse [PixArt Lenovo Optical USB Mouse] on usb-fd8c0000.usb-1/input0

[1058.921] event5 - PixArt Lenovo Optical USB Mouse: is tagged by udev as: Mouse

[1058.923] event5 - PixArt Lenovo Optical USB Mouse: device is a pointer

[1058.930] libinput: configuring device "PixArt Lenovo Optical USB Mouse".

[1058.937] associating input device event5 with output LVDS-1 (none by udev)

从上述内容可道,linux内核提示识别到了一个新的low-speedUSB(低速设备),并且得到了关于该USB鼠标相关的参数信息。然后input输入子系统打印出了两条信息:

[ 3122.713317] input: PixArt Lenovo Optical USB Mouse as /devices/platform/fd8c0000.usb/usb4/4-1/4-1:1.0/00036019.0004/input/input8

[ 3122.771015] hid-generic 00036019.0004: input,hidraw0: USB HID v1.11 Mouse [PixArt Lenovo Optical USB Mouse] on usb-fd8c0000.usb-1/input0

接着用户空间程序打印出了几条信息:

[1058.921] event5 - PixArt Lenovo Optical USB Mouse: is tagged by udev as: Mouse

[1058.923] event5 - PixArt Lenovo Optical USB Mouse: device is a pointer

[1058.930] libinput: configuring device "PixArt Lenovo Optical USB Mouse".

[1058.937] associating input device event5 with output LVDS-1 (none by udev)

至此,可以知道当USB鼠标插入usb接口后,linux内核会识别到usb设备插入并且打印出识别到的信息,然后会交给input输入子系统识别,因为鼠标是一个输入设备,应归属于输入子系统下,输入子系统会向用户空间暴露出操作接口。接着用户空间程序检测到用户的输入识别进而打印出相关的识别信息,从而完成整个识别过程。

从内核源码角度,usb内核识别阶段打印设备描述符信息的操作函数是announce_device(),实现如下:

static void announce_device(struct usb_device *udev)

{

u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);

dev_info(&udev->dev,

"New USB device found, idVendor=%04x, idProduct=%04x, bcdDevice=%2x.%02x

",

le16_to_cpu(udev->descriptor.idVendor),

le16_to_cpu(udev->descriptor.idProduct),

bcdDevice >> 8, bcdDevice & 0xff);

dev_info(&udev->dev,

"New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d

",

udev->descriptor.iManufacturer,

udev->descriptor.iProduct,

udev->descriptor.iSerialNumber);

show_string(udev, "Product", udev->product);

show_string(udev, "Manufacturer", udev->manufacturer);

show_string(udev, "SerialNumber", udev->serial);

}

#elsestatic inline void announce_device(struct usb_device *udev) { }

#endif

(2-2)USB鼠标移除/拔下后日志分析

当usb设备移除后,则会打印出类似以下的信息:

(1)[ 2791.684059] usb 4-1: USB disconnect, device number 4

(2)[1027.777] event5 - PixArt Lenovo Optical USB Mouse: device removed

第(1)条信息是linux内核usb核心识别到usb设备被移除/拔出后,打印出的信息,这个过程是内核空间的过程。

第(2)条信息是用户空间程序识别到usb鼠标设备被拔出后打印出的信息,这个过程是用户空间程序的操作过程。

三、 usb host控制器的初始化

一般情况下,处理器平台内部都集成了USB host主机控制器,linux内核中,对usb host控制器的初始化发生在内核启动阶段,从内核启动打印出的日志中,可以找到类似如下的信息(输出中加有标记信息):

[ 0.779954] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1

[ 0.779969] usb usb1: Product: EHCI Host Controller

[ 0.779978] usb usb1: Manufacturer: Linux 4.19.232 ehci_hcd

[ 0.779991] usb usb1: SerialNumber: fd800000.usb

[ 0.780002]

[ 0.780002] ================usb_new_device==============

[ 0.780432] ==================================enter hub_probe=============================

[ 0.780453] hub 1-0 USB hub found

[ 0.780493] hub 1-0 1 port detected

[ 0.783005] ehci-platform fd880000.usb: EHCI Host Controller

[ 0.783186] ehci-platform fd880000.usb: new USB bus registered, assigned bus number 2

[ 0.783503] ehci-platform fd880000.usb: irq 14, io mem 0xfd880000

[ 0.796390] ehci-platform fd880000.usb: USB 2.0 started, EHCI 1.00

[ 0.796606] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 4.19

[ 0.796626] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1

[ 0.796641] usb usb2: Product: EHCI Host Controller

[ 0.796655] usb usb2: Manufacturer: Linux 4.19.232 ehci_hcd

[ 0.796669] usb usb2: SerialNumber: fd880000.usb

[ 0.796680]

[ 0.796680] ================usb_new_device==============

[ 0.797080] ==================================enter hub_probe=============================

[ 0.797100] hub 2-0 USB hub found

[ 0.797142] hub 2-0 1 port detected

[ 0.797861] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver

[ 0.797892] ohci-platform: OHCI generic platform driver

[ 0.798121] ohci-platform fd840000.usb: Generic Platform OHCI controller

[ 0.798290] ohci-platform fd840000.usb: new USB bus registered, assigned bus number 3

[ 0.798541] ohci-platform fd840000.usb: irq 13, io mem 0xfd840000

[ 0.857203] usb usb3: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 4.19

[ 0.857224] usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1

[ 0.857239] usb usb3: Product: Generic Platform OHCI controller

[ 0.857252] usb usb3: Manufacturer: Linux 4.19.232 ohci_hcd

[ 0.857265] usb usb3: SerialNumber: fd840000.usb

[ 0.857276]

[ 0.857276] ================usb_new_device==============

[ 0.857683] ==================================enter hub_probe=============================

[ 0.857703] hub 3-0 USB hub found

[ 0.857750] hub 3-0 1 port detected

[ 0.858206] ohci-platform fd8c0000.usb: Generic Platform OHCI controller

[ 0.858386] ohci-platform fd8c0000.usb: new USB bus registered, assigned bus number 4

[ 0.858624] ohci-platform fd8c0000.usb: irq 15, io mem 0xfd8c0000

[ 0.917200] usb usb4: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 4.19

[ 0.917220] usb usb4: New USB device strings: Mfr=3, Product=2, SerialNumber=1

[ 0.917234] usb usb4: Product: Generic Platform OHCI controller

[ 0.917248] usb usb4: Manufacturer: Linux 4.19.232 ohci_hcd

[ 0.917260] usb usb4: SerialNumber: fd8c0000.usb

[ 0.917271]

[ 0.917271] ================usb_new_device==============

[ 0.917662] ==================================enter hub_probe=============================

[ 0.917683] hub 4-0 USB hub found

[ 0.917740] hub 4-0 1 port detected

[ 0.919175] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller

[ 0.919378] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 5

[ 0.919920] xhci-hcd xhci-hcd.0.auto: hcc params 0x0220fe64 hci version 0x110 quirks 0x0000011002010010

[ 0.919992] xhci-hcd xhci-hcd.0.auto: irq 81, io mem 0xfd000000

[ 0.920297] usb usb5: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 4.19

[ 0.920316] usb usb5: New USB device strings: Mfr=3, Product=2, SerialNumber=1

[ 0.920331] usb usb5: Product: xHCI Host Controller

[ 0.920344] usb usb5: Manufacturer: Linux 4.19.232 xhci-hcd

[ 0.920357] usb usb5: SerialNumber: xhci-hcd.0.auto

[ 0.920369]

[ 0.920369] ================usb_new_device==============

[ 0.920786] ==================================enter hub_probe================

[ 0.920806] hub 5-0 USB hub found

[ 0.920849] hub 5-0 1 port detected

[ 0.921167] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller

[ 0.921325] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assignStarting syslogd: ed bus number 6

[ 0.921352] xhci-hcd xhci-hcd.0.auto: Host supports OK

USB 3.0 SuperSpeed

[ 0.921433] usb usb6: We don't know the alStarting klogd: gorithms for LPM for this host, disabling LPM.

[ 0.921559] usbOK

usb6: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 4.19

[ 0.921577]Populating /dev using udev: usb usb6: New USB device strings: Mfr=3, Product=2, SerialNumber=1

[ 0.921593] usb usb6: Product: xHCI Host Controller

[ 0.921607] usb usb6: Manufacturer: Linux 4.19.232 xhci-hcd

[ 0.921620] usb usb6: SerialNumber: xhci-hcd.0.auto

[ 0.921630]

[ 0.921630] ================usb_new_device============

[ 0.922028] ====================enter hub_probe=============================

=============

[ 0.922047] hub 6-0 USB hub found

[ 0.922086] hub 6-0 1 port detected

在linux USB子系统中,需使用usb_register_bus()将USB host控制器注册到USB核心上,该函数由usb_add_hcd()调用,用于完成通用hcd结构的初始化和注册,并调用驱动程序的reset()和start()。

我们已经知道,在usb通信机制中,处理器内部一般都会集成host控制器,所以同样需要有对应的驱动程序去驱动。usb_add_hcd()函数则会在usb的主机控制器驱动程序的probe过程中被调用,内核中,几乎所有的usb host控制器驱动都是这样的写法。

在USB Host控制器驱动框架下,有一个重要的数据结构:struct usb_hcd,用于描述一个USB Host Controller Driver(简写HCD)。例如通用平台ohci驱动,驱动文件则是:ohci-platform.c,源码中有如下代码:

usb_create_hcd用于创建并初始化一个hcd结构描述符:

usb_add_hcd用于初始化hcd结构和注册hcd:

调用platform_get_irq()为设备分配中断号:

在usb_add_hcd()中会调用usb_hcd_request_irqs():

从上图可知,其会调用request_irq()这个重磅函数为ohci host控制器分配中断,中断处理函数为usb_hcd_irq ():

irqreturn_t usb_hcd_irq (int irq, void *__hcd)

{

struct usb_hcd *hcd = __hcd;

irqreturn_t rc;

if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))

rc = IRQ_NONE;

else if (hcd->driver->irq(hcd) == IRQ_NONE)

rc = IRQ_NONE;

else

rc = IRQ_HANDLED;

return rc;

}

仔细分析上述代码,又回去了:在hcd中断处理函数中则会去调用执行hcd驱动程序指定的irq:

hcd->driver->irq(hcd)

那么对于ohci控制器来说,irq则是ohci_irq(),如下图所示:

综上,如果处理器内部usb host控制器符合ohci通用标准,则可以使用ohci-platform.c下的驱动程序,这意味着当ohci类的usb设备插入时,对应的中断处理函数会被调用执行(小生根据实际源码运行验证过,也确实如此)

在linux内核中,对于ehci和xhci的host控制器,同样有对应的通用驱动程序。只要处理器平台内部USB host控制器符合linux内核提供的通用驱动即可使用。

四、USB设备插入后的硬件过程

从linux内核源码反推硬件对插入的USB设备的识别,大概知道这个过程是由处理器内部的host控制器完成的。当插入USB设备后,将触发对应的usb host控制器的中断,中断进而又由中断控制器捕获,从而将中断信息由硬件转向linux内核的中断系统,从前面分析可知,USB host控制器驱动程序都为对应的控制器指定了中断处理函数,那么在中断处理函数中,则会读取控制器的寄存器参数值从而获取控制器状态,除此之外在中断处理函数中还做了很多事情(标准xhci控制器驱动程序的写法与ohci、ehci标准控制器驱动有很大不同,暂不过多深究!),例如调用usb_hcd_poll_rh_status(),但目的只有一个:激活刷新usb hub。

五、USB设备插入后的软件过程

当usb hub被激活刷新后,其后会调用到hub_event,后续的调用逻辑如下:

hub_events()->hub_port_connect_change()->hub_port_connect()->usb_new_device()

->device_add()->kobject_uevent()

usb_new_device()是创建usb新设备的核心函数,在linux内核启动过程中或者插入usb设备后,USB核心会调用这个函数。

kobject_uevent()用于向用户空间发送uevent事件,通知用户空间的侦听程序USB设备已经插入。

『笔者在浏览查询资料时,发现了这个问题,在此一并列出』

Q1:如果USB设备的驱动是在设备插入时动态加载的,那这个加载过程,处在这一个过程的哪一个位置?

A1:调用bus_probe_device(dev)完成!

综上,得出结论:在linux内核中,一个USB设备插入时,其设备驱动是动态加载的

审核编辑:陈陈

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

    关注

    60

    文章

    7888

    浏览量

    263926
  • Linux
    +关注

    关注

    87

    文章

    11219

    浏览量

    208872
  • 热插拔
    +关注

    关注

    2

    文章

    217

    浏览量

    37202

原文标题:不放过linux-usb的热插拔过程

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

收藏 人收藏

    评论

    相关推荐

    热插拔是什么?热插拔有哪些特点?

    的电脑中一般都有USB接口,这种接口就能够实现热插拔。如果没有热插拔功能,即使磁盘损坏不会造成数据的丢失,用户仍然需要暂时关闭系统,以便能够对硬盘进行更换,而使用
    发表于 12-13 10:53

    即插即用和热插拔的区别

    关系。即插即用是要重启机器才能认出来的热插拔立刻就能认出来 支持即插即用是一种使您可以快速简易安装某硬件设备而无需安装设备驱动程序或重新配置系统的标准。即插即用需要硬件和软件两方面支持,Windows
    发表于 10-23 10:26

    如何对BMS单元连接进行热插拔

    注重序列效果的情况下,重复测试是可能的。这使得能够测试多个设备。序列有效性减少测试时间,因此人员可以安全的角度出发。最后,测试过程的定时可以扩展到模拟工厂/用户连接过程中自然发生的延
    发表于 09-07 18:20

    基于Linux的Netlink热插拔监控

    Linux中Netlink实现热插拔监控——内核与用户空间通信
    发表于 03-19 11:42

    热插拔系统的影响主要有哪些

    现在大多数电子系统都要支持热插拔功能,所谓热插拔,也就是在系统正常工作时,带电对系统的某个单元进行插拔
    发表于 10-29 06:51

    怎么通知应用层cp2102芯片的热插拔状态?

    在用iMX6UL开发板,U盘可以内核层面实现热插拔。我现在有个USB转串口的设备(cp2102芯片),不知道有没有朋友知道怎么通知应用层该设备的
    发表于 01-11 06:31

    USB转串口热插拔无法实现是为什么?

    在用iMX6UL开发板,U盘可以内核层面实现热插拔。我现在有个USB转串口的设备(cp2102芯片),不知道有没有朋友知道怎么通知应用层该设备的
    发表于 01-11 07:40

    热插拔装置软件

    热插拔装置软件USB Safely Remove是一款支持热插拔装置和迅速切断一个公用的热插拔装置的软件
    发表于 04-23 09:32 151次下载

    基于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>输入<b class='flag-5'>子系统</b>的驱动研究

    热插拔控制电路的分析和设计过程

    系统其余部分的情况下进行替换,在系统维持运转的情况下,发生故障的电路板或模块将被移除,同时替换部件被插入。这个过程被称为热插拔(hot swapping)(当模块与
    发表于 06-05 15:29 8654次阅读
    <b class='flag-5'>热插拔</b>控制电路的<b class='flag-5'>分析</b>和设计<b class='flag-5'>过程</b>

    如何使用Linux内核实现USB驱动程序框架

    Linux内核提供了完整的USB驱动程序框架。USB总线采用树形结构,在一条总线上只能有唯一的主机设备。 Linux
    发表于 11-06 17:59 20次下载
    如何使用<b class='flag-5'>Linux</b><b class='flag-5'>内核</b>实现<b class='flag-5'>USB</b>驱动程序框架

    linux-usb子系统的核心描述

    本文将描述linux-usb子系统的核心,主要分析其核心的初始化流程,文中源码基于内核版本:4.1.15。
    的头像 发表于 01-14 09:37 2626次阅读

    热插拔和非热插拔的区别

    系统关闭或待机状态下进行。 热插拔技术的出现,极大地方便了电子设备的使用和维护,减少了因为插拔设备而导致的系统的关机和停机时间,并且降低了设备故障和损坏的风险。下面将从硬件和
    的头像 发表于 12-28 10:01 2805次阅读

    键盘热插拔和非热插拔的区别

    、电源供应、软件驱动、使用便利性、设备损坏与安全性、推动产业发展等。 1. 连接方式 热插拔键盘通常使用USB或无线连接方式,插入即可立即生效。非热插拔键盘一般使用PS/2接口连接,插
    的头像 发表于 02-02 17:34 9625次阅读