USB总线-Linux内核USB3.0设备控制器中断处理程序分析(九)
1.概述
USB设备枚举、请求处理、数据交互都涉及USB设备控制器中断。当有事件发生时,USB设备控制器首先将事件信息通过DMA写入到事件缓冲区中,然后向CPU发出中断,随后CPU调用中断处理函数开始处理中断事件。
2.事件
dwc3 USB设备控制器事件使用dwc3_event数据结构描述,由4个字节组成。按位域区区分,可分为3类事件,分别为设备端点事件、设备事件及其他核心事件。dwc3_event_type用来描述事件的类型,is_devspec == 1表示事件为设备事件,否则表示设备端点事件。dwc3_event_depevt描述设备端点事件,包含了产生事件的端点编号、具体的事件、事件状态等信息。dwc3_event_devt描述设备控制器事件,包含了具体的设备事件、事件类型、事件信息等。dwc3_event_gevt使用的不多,这里不详细介绍。
[drivers/usb/dwc3/core.h]
/**
* union dwc3_event - representation of Event Buffer contents
* @raw: raw 32-bit event
* @type: the type of the event
* @depevt: Device Endpoint Event
* @devt: Device Event
* @gevt: Global Event
*/
union dwc3_event {
u32 raw;
struct dwc3_event_type type; // 事件类型
struct dwc3_event_depevt depevt; // Device Endpoint Events
struct dwc3_event_devt devt; // Device Events
struct dwc3_event_gevt gevt; // 全局事件
};
struct dwc3_event_type {
u32 is_devspec:1; // 是否是设备事件
u32 type:7; // 事件类型
u32 reserved8_31:24; // 保留
} __packed;
[drivers/usb/dwc3/core.h] /* dwc3 USB设备端点事件宏定义 / #define DWC3_DEPEVT_XFERCOMPLETE 0x01 // 传输完成 #define DWC3_DEPEVT_XFERINPROGRESS 0x02 // 传输正在处理中 #define DWC3_DEPEVT_XFERNOTREADY 0x03 // 传输未准备好 // 接收和发送FIFO事件 (IN->Underrun, OUT->Overrun) #define DWC3_DEPEVT_RXTXFIFOEVT 0x04 #define DWC3_DEPEVT_STREAMEVT 0x06 // 流事件 #define DWC3_DEPEVT_EPCMDCMPLT 0x07 // 端点命令完成 struct dwc3_event_depevt { / USB设备端点事件 */ u32 one_bit:1; // 未使用 u32 endpoint_number:5; // 端点编号 u32 endpoint_event:4; // 端点事件 u32 reserved11_10:2; u32 status:4; // 端点事件状态 u32 parameters:16; } __packed;
3.事件缓冲区
dwc3事件保存在dwc3_event_buffer数据结构中,各个成员的意义如下。事件保存在buf中,dma是buf的DMA地址,事件数据由DMA传输到buf中,lpos是缓冲区中已处理事件的偏移,count表示缓冲区中的事件数量。事件使用dwc3_event数据结构描述,上面已经介绍过了。不同的事件,有不同的处理方法。
[drivers/usb/dwc3/core.h]
/* 事件缓冲区数据结构 */
struct dwc3_event_buffer {
void *buf; // 事件缓冲区地址
unsigned length; // 事件缓冲区长度
unsigned int lpos; // 事件缓冲区偏移
unsigned int count; // 缓存最近一次产生事件的数量
unsigned int flags; // 事件缓冲区标志
#define DWC3_EVENT_PENDING BIT(0)
dma_addr_t dma; // 事件缓冲区DMA地址
struct dwc3 *dwc; // 指向DWC控制器数据结构
};
dwc3_event_buffer数据结构的初始化过程如下:
- 在
dwc3_probe函数中,调用dwc3_alloc_event_buffers函数分配dwc3_event_buffer结构体,调用dma_alloc_coherent分配buf,长度为4096字节,记录虚拟地址和DMA地址。 - 在
dwc3_core_init函数中,调用dwc3_event_buffers_setup函数,将buf的DMA地址、长度分别写入USB设备控制器对应的寄存器,将事件数量寄存器和缓冲区偏移清零。
4.事件处理
dwc3 USB设备控制器的事件分为两步处理。第一步在中断上半部分处理,只记录事件数量,第二步在中断下半部(线程)处理,遍历事件缓冲区,循环处理所有事件。
4.1.中断上半部分
dwc3 USB3.0设备控制器事件的中断上半部分处理流程如下图所示。首先保存全局事件数量,设置事件pending标志,接着屏蔽控制器的中断,最后返回IRQ_WAKE_THREAD,唤醒中断处理线程。可以看出,中断上半部分很简单,只做了读写寄存器和保存状态的工作,不涉及具体事件的处理。

4.2.中断下半部分
dwc3 USB3.0设备控制器的中断下半部分处理流程如下图所示。事件处理是在持有自旋锁和关中断的情况进行的。在dwc3_process_event_buf函数中,循环处理所有事件。处理完毕,将事件数量和事件pending标记清零,最后重新打开中断并退出。
dwc3_process_event_entry函数负责处理一个具体的事件,根据事件类型,又分为端点事件和设备事件,端点事件调用dwc3_endpoint_interrupt函数处理,设备事件调用dwc3_gadget_interrupt函数处理。端点事件和设备事件下又分了很多具体的事件,比较复杂,碍于篇幅,这里只介绍端点0的事件。

4.2.1.端点0事件
端点0事件调用dwc3_ep0_interrupt函数处理,处理流程如下图所示。对于DWC3_DEPEVT_XFERINPROGRESS、DWC3_DEPEVT_RXTXFIFOEVT、DWC3_DEPEVT_STREAMEVT、DWC3_DEPEVT_EPCMDCMPLT事件,驱动程序不做额外的处理,直接返回。当端点0产生DWC3_DEPEVT_XFERCOMPLETE事件时,其对应端点0控制传输的三个状态,分别为建立阶段、数据阶段和状态阶段,其中数据阶段可选。具体可参考http://www.usbzh.com/article/detail-55.html。下面分析一下dwc3 USB设备控制器驱动对这个三个阶段的处理。

- EP0_SETUP_PHASE
在调用dwc3_gadget_start使能USB设备控制器时,端点0的状态被设置为EP0_SETUP_PHASE,等待接收来自主机的SETUP数据包,接收到SETUP数据包后控制器产生DWC3_DEPEVT_XFERCOMPLETE事件,根据端点0状态进入dwc3_ep0_inspect_setup函数进行处理。主机发送的SETUP数包可分为两类,一类是标准的USB请求,如USB_REQ_GET_STATUS、USB_REQ_CLEAR_FEATURE、USB_REQ_SET_FEATURE等,调用dwc3_ep0_std_request函数处理。非标准请求调用dwc3_ep0_delegate_req函数处理。在dwc3_ep0_std_request函数中,驱动处理了一部分标准的USB请求,如获取和设置设备或端点的特性、状态等,其他复杂的请求,调用dwc3_ep0_delegate_req函数处理。dwc3_ep0_delegate_req函数内部会调用上层USB gadget driver提供的set_up函数,即composite_setup函数。
composite_setup函数的处理流程如下图所示。按主机发送的USB请求进行处理,分为标准的USB请求和非标准的USB请求。非标准的USB请求最终通过调用uac2驱动的afunc_setup函数处理。最后判断是否有数据要传输,如USB_REQ_GET_DESCRIPTOR请求是需要数据阶段的,若需要,则会调用composite_ep0_queue将数据发送到端点0,同时将端点的状态设置为EP0_DATA_PHASE。
usb_ctrlrequest各个字段的定义如下图所示。USB标准请求bRequest字段的bit[5-6]位都为0。若bRequest字段的bit[5-6]位为01,则是USB类设备定义的命令,需要USB类设备驱动处理。下面是uac2设备接收的USB请求,需要调用uac2驱动的afunc_setup函数处理。
bRequestType = 0xa1
bRequest = 0x2
wValue = 0x100
wIndex = 0x500
wLength = 0x100
- EP0_DATA_PHASE
在EP0_SETUP_PHASE阶段之后,若需要传输数据,则会有EP0_DATA_PHASE阶段。数据传输完成后,产生DWC3_DEPEVT_XFERCOMPLETE事件,根据当前端点0的状态,进入dwc3_ep0_complete_data函数处理。dwc3_ep0_complete_data的主要工作是判断端点0是否还有数据要传输,若需要先回调usb_request的回调函数,接着启动传输,反之直接返回。
- EP0_STATUS_PHASE
EP0_STATUS_PHASE由DWC3_DEPEVT_XFERNOTREADY事件设置。此阶段由dwc3_ep0_complete_status函数处理,主要的工作准备TRB,为下一次的控制传输的SETUP做准备。
端点0的DWC3_DEPEVT_XFERNOTREADY事件主要用于指出当前请求的传输阶段是数据阶段还是状态阶段。具体由dwc3_event_depevt的status字段决定。若是数据阶段且还有未发送完的数据,则会忽略;若是状态阶段,则首先设置端点0的状态为EP0_STATUS_PHASE,接着传输状态阶段(DWC3_TRBCTL_CONTROL_STATUS3/DWC3_TRBCTL_CONTROL_STATUS2)的数据包。
当状态阶段的数据包传输完成后,产生DWC3_DEPEVT_XFERCOMPLETE事件,此时就进入了EP0_STATUS_PHASE的处理逻辑。
USB总线-Linux内核USB3.0设备控制器中断处理程序分析(九)的更多相关文章
- 如何在Ubuntu/CentOS上安装Linux内核4.0
大家好,今天我们学习一下如何从Elrepo或者源代码来安装最新的Linux内核4.0.代号为‘Hurr durr I'm a sheep’的Linux内核4.0是目前为止最新的主干内核.它是稳定版3. ...
- 安装 Linux 内核 4.0
大家好,今天我们学习一下如何从Elrepo或者源代码来安装最新的Linux内核4.0.代号为‘Hurr durr I'm a sheep’的Linux内核4.0是目前为止最新的主干内核.它是稳定版3. ...
- Linux内核中的list用法和实现分析
这些天在思考知识体系的完整性,发现总是对消息队列的实现不满意,索性看看内核里面的链表实现形式,这篇文章就当做是学习的i笔记吧.. 内核代码中有很多的地方使用了list,而这个list的用法又跟我们平时 ...
- Linux内核3.0移植并基于Initramfs根文件系统启动
Linux内核移植与启动 Target borad:FL2440 Bootloader:U-boot-2010.09 交叉编译器:buildroot-2012.08 1.linux内核基础知识 首先, ...
- Linux内核驱动--mmap设备方法【原创】
mmap系统调用(功能) void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) 内存映射函数mma ...
- Linux内核编程-0:来自内核的 HelloWorld
Linux内核编程一直是我很想掌握的一个技能.如果问我为什么,我也说不上来. 也许是希望有一天自己的ID也出现在内核开发组的邮件列表里?或是内核发行文件的CREDITS文件上? 也许是吧.其实更多的, ...
- 分析Linux内核5.0系统调用处理过程
学号: 363 本实验来源 https://github.com/mengning/linuxkernel/ 一.实验要求 1.编译内核5.02.qemu -kernel linux-5.0.1/ar ...
- Linux内核中进程上下文、中断上下文、原子上下文、用户上下文的理解【转】
转自:http://blog.csdn.net/laoliu_lcl/article/details/39972459 进程上下文和中断上下文是操作系统中很重要的两个概念,这两个概念在操作系统课程中不 ...
- Linux内核中进程上下文和中断上下文的理解
參考: http://www.embedu.org/Column/Column240.htm http://www.cnblogs.com/Anker/p/3269106.html 首先明白一个概念: ...
- Linux内核调试方法总结之死锁问题分析
死锁问题分析 死锁就是多个进程(线程)因为等待别的进程已占有的自己所需要的资源而陷入阻塞的一种状态,死锁状态一旦形成,进程本身是解决不了的,需要外在的推动,才能解决,最重要的是死锁不仅仅影响进程业务, ...
随机推荐
- 【Java】Spring5学习
基础环境与文档资料: 见黑马视频: https://www.bilibili.com/video/BV1P44y1N7QG 依赖坐标: <?xml version="1.0" ...
- 【Spring Data JPA】05 方法名限定查询
方法名限定查询 方法名限定查询是对JPQL的再封装 按照SpringData提供的方法名定义方法,不需要配置JPQL语句即可完成查询 在IDEA中都有相应的提示 他会按照方法字符判断 public C ...
- 国产的AI基础设施与国外的差距?仅以grpc与prpc做比较
搞AI,基础设施包括软件.硬件以及相关生态,多方面,这里只片面的取一个例子来说明国内外在AI基础设施上的区别,注意,这里只是片面截取. 高性能的rpc框架是搞AI的一个基础依赖软件,当然,国外也有与之 ...
- 《Python数据可视化之matplotlib实践》 源码 第一篇 入门 第四章
图 4.1 import matplotlib import matplotlib.pyplot as plt import numpy as np # 设置matplotlib正常显示中文和负号 m ...
- 【转载】 【树莓派】为Ubuntu Mate for ARM 更换中国软件源
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/wr132/article/details ...
- 如何拉取指定CPU架构并且指定ubuntu版本并且指定cuda和cudnn版本的docker镜像
本篇讲的重点是如何拉取带有cuda和cudnn的docker镜像,因此这些的镜像源的频道为NVIDIA: 官方地址: https://hub.docker.com/r/nvidia/cuda 根据官方 ...
- 解决CGLib动态代理测试不通过-Unable to load cache item
1.背景 在学习aop底层时遇到的问题,做个小结 2.现象 动态代理代码如下: package com.ldp.proxy; import net.sf.cglib.proxy.Enhancer; i ...
- Linux的netns使用总结
转载请注明出处: Linux的netns(Network Namespace)是Linux内核提供的一项强大的网络隔离功能,它能够创建多个独立的网络空间,每个空间都拥有自己独立的网络协议栈,包括网络接 ...
- ElementUI.Dialog.props怎么设置全局变量
在main.js中为啥?这个可以 ElementUI.Dialog.props.closeOnClickModal.default = false // 全局关闭点遮罩关闭弹框 为啥这个不可以? El ...
- 一种很变态但有效的DDD建模沟通方式
本文书接上回<这就是为什么你学不会DDD>,关注公众号(老肖想当外语大佬)获取信息: 最新文章更新: DDD框架源码(.NET.Java双平台): 加群畅聊,建模分析.技术实现交流: 视频 ...