高通SDX55平台:adb功能异常

news/2023/12/2 10:10:22

高通SDX55平台:adb功能异常

  • 1. 问题描述
  • 2. 问题分析
    • 2.1 测试环境
    • 2.2 初步分析
    • 2.3 USB驱动初始化
      • 2.3.1 USB驱动加载流程
        • 2.3.1.1 USB_init初始化
        • 2.3.1.2 usb_hub_init
        • 2.3.1.3 usb设备插入后usbufs驱动加载
      • 2.3.2 adb请求后usbfs设备驱动初始化流程
    • 2.4 adb接口枚举流程分析
      • 2.4.1 adb架构
      • 2.4.2 adb devices流程
    • 2.5 关键log解读
  • 3 问题小结
    • 3.1 问题根因
    • 3.2 解决方法
    • 3.3 小结

1. 问题描述

在Linux环境上使用SDX55模块时出现无法识别adb端口,但可以识别手机adb端口。

2. 问题分析

2.1 测试环境

内核:Linux 4.19.26
系统:CentOS Linux release 7.8.2003
Modem:高通SDX55
连接方式:USB3.0(M.2)

2.2 初步分析

通过分析dmesg log发现,手机与Linux设备连接使用的端口是USB2.0,而模块与Linux设备连接的端口是USB3.0。初步分析可能由于USB2.0和USB3.0的差异或者客户USB3.0的硬件有问题导致。再次对比测试,将SDX55模块通过USB2.0方式连接到Linux设备,发现可以正常识别adb端口。进一步确认我们的分析。由于adb涉及到的问题主要从主机侧驱动、主机侧adb、模块adbd状态来排查。接下来我们将对这些情况进行一一排查来确定问题:

  1. USB驱动初始化是否正常
  2. 主机侧adb是否正常
  3. 模块侧adbd确定是否正常

2.3 USB驱动初始化

由于对adb流程不熟悉,因此先排查一下USB内核驱动相关的初始化是否正常。

2.3.1 USB驱动加载流程

2.3.1.1 USB_init初始化

USB内核框架的代码在linux-4.19.26/drivers/usb目录下,入口函数为usb_init,在内核启动过程中加载执行,其代码如下图:
kernel\drivers\usb\core\usb.c:在这里插入图片描述
usb_init用于初始化usb内核框架,主要进行以下初始化:

  1. USB debugfs初始化:创建字符设备/sys/kernel/debug/usb/devices,读取该字符设备可以得到usb总线拓扑结构、带宽、设备描述信息、产品标识信息、serialnumber信息、配置描述信息和端点描述信息。在lsusb命令不可用的时候,可以为usb驱动提供丰富的调试信息。
  2. 总线注册:这个就是将usb总线注册到系统总线上,注册的USB总线类型如下图:
    在这里插入图片描述
  3. 注册USB总线通知链
    在这里插入图片描述
  4. 初始化usb主控器字符设备:cat /proc/devices可以看到(#define USB_MAJOR 180)
  5. 注册usbfs驱动:注册后的驱动将在/sys/bus/usb/drivers创建节点,该节点可以看到哪些设备加载usbfs,当前模块adb使用的便是usbfs。usbfs为提供了在用户空间直接访问usb硬件设备接口的能力。usbfs驱动不需要host进行加载,当上层应用调用的时候usbfs驱动自动加载识别设备。
    在这里插入图片描述
  6. usb字符设备初始化(#define USB_DEVICE_MAJOR 189)
  7. usb hub初始化
  8. 将generic.c里面的 usb_generic_driver 加入到usb总线下的驱动链表里

usb驱动的匹配过程主要在hub初始化里面实现,接下里看一下hub初始化的流程。

2.3.1.2 usb_hub_init

kernel\drivers\usb\core\hub.c:在这里插入图片描述
usb_hub_init主要做了以下事情:

  1. 将hub driver注册到usb驱动列表
  2. 创建hub_wq:这个worker跟usb hub event处理相关联,用来处理usb总线上的设备状态,连接状态事件。

usb_hub_init调用usb_register将hub_driver注册到usb总线驱动的列表里。然后调用hub_driver.probe加载hub驱动,hub_driver如下图:
在这里插入图片描述
hub_probe调用hub_configure注册了中断,一旦接入新的usb设备就会调用hub_irq
在这里插入图片描述
然后hub_irq中断处理完成后,开启hub_wq线程(kick_hub_wq(hub);)调用hub_event处理usb插入事件。下面详细介绍一下。

2.3.1.3 usb设备插入后usbufs驱动加载

当usb设备插入之后usb总线会识别出adb端口,并且找到匹配的usbfs驱动加载,从而你完成adb设备的驱动初始化。当设备插入中断触发后,hub_irq处理中断后开启workqueue hub_wq调用hub_event处理插入事件。下面梳理一下流程。
hub_event调用遍历所有的port处理port event:
在这里插入图片描述
port_event调用hub_port_status进而调用hub_ext_port_status来处理端口事件:
在这里插入图片描述
如hub_ext_port_status获取到的hub port状态为0x203,即表示当前port有设备连接:
在这里插入图片描述
从port_event调用hub_port_connect_change最后调用到hub_port_connect,hub_port_connect主要作用是创建设备、给新设备选择新的编号,获取设备的各种描述符,然后调用usb_new_device注册新设备。
hub_port_connect
->choose_devnum 给新设备选择新的编号(地址)
->hub_port_init 把编号(地址)告诉USB设备,以后就使用这个地址了
->usb_new_device
usb_new_device调用usb_enumerate_device获取usb描述符
在这里插入图片描述
注:设备描述符在hub_port_init里面获取

如下图获取配置描述符,usb_get_configuration首先从设备描述符里面获取配置描述符的数量,然后遍历所有配置描述符并获取,将获取到描述符格式化到dev->rawdescriptors[cfgno]里面。
在这里插入图片描述
其他描述符这里不多赘述,只讲一下usb3.0和usb2.0的差异。usb3.0有超高速伙伴描述符usb_ss_ep_comp_descriptor,所以只有usb3.0会获取它,usb2.0是不会获取这个描述符的。如下图:
在这里插入图片描述
由于usb超高速伙伴描述符sizeof()=USB_DT_SS_EP_COMP_SIZE=6,保存该描述符后将buffer+6:
在这里插入图片描述
此时,所有的usb描述符都获取完毕,并解析保存完毕。

接下来回到usb_new_device,接下来调用add_device,此时usb总线匹配设备驱动,此时新插入的usb将于usb_init注册的驱动usb_generic_driver匹配,总线接下来加载该驱动识别并加载usb interface和驱动。

generic_probe做了两件事1、获取设备配置,2、应用配置。对usb设备的interface、endpoint进行设备注册与配置。
在这里插入图片描述
usb_set_configuration设置interface属性:
在这里插入图片描述
然后将interface设备加入到系统,然后初始化每个 interface对应的endpoint。add_device将match对应的interface设备驱动,总线将自动加载对应的驱动。
在这里插入图片描述
接下来编译interface的每个endpoint进行配置,将设备添加进系统中
在这里插入图片描述
至此内核驱动的初始化就完成了,当上层adb应用请求连接建立时将动态将usbfs设备驱动与设备进行关联,并加载驱动。也可以看一下usbfs驱动在usb_init时已经注册,他的probe函数是一个空函数,只有当上层adb设备请求的时候才会进行设备匹配。

2.3.2 adb请求后usbfs设备驱动初始化流程

当adb向usbfs驱动发起USBDEVFS_CLAIMINTERFACE请求后,此时将进行USB设备与usbfs驱动设备的绑定。
如下图为usb devio注册的函数,adb server发起的请求由usb devio进行处理:
在这里插入图片描述
adb的请求由usbdev_ioctl进行处理:
在这里插入图片描述
最终调用到claimintf,claimintf函数将进行ad端口与usbfs驱动进行绑定:
在这里插入图片描述
至此所有的驱动侧就完成了。

2.4 adb接口枚举流程分析

adb源码:https://android.googlesource.com/platform/system/core/
可在以上链接获取adb源码集成到项目中。本次问题出现在adb server端,本文后续内容只对host侧adb server的相关代码进行解读,不涉及adbd和adb clinet。

2.4.1 adb架构

adb由两个物理文件组成adb和adbd。adb client和adb server运行在host端,adbd守护进程运行在device侧,host和device通过tcp连接。
在这里插入图片描述

2.4.2 adb devices流程

adb main函数调用adb_commandline对adb参数进行拼接组成adb command line。
在这里插入图片描述
adb_commandline调用adb_query_command然后调用adb_query查询adb server状态,如果adb server未运行则启动adb server:
在这里插入图片描述
launch_server在5037端口运行adb server,此时adb进程fork一个子进程,此时adb devices返回。子进程执行“adb –P 5037 fork-server server”启动adb server:
在这里插入图片描述
在这里插入图片描述
adb判断子进程需要启动server,调用adb_main启动adb server:
在这里插入图片描述
然后启动线程find usb devices:
在这里插入图片描述
在这里插入图片描述
如上图,find_usb_device读取字符设备/dev/bus/usb/ b u s i d / {bus_id}/ busid/{device_id}获取设备各种描述符:
在这里插入图片描述
在这里插入图片描述
然后跳过设备描述符和配置描述符:
在这里插入图片描述接下来在interface描述符里面查找adb端口,adb对应的interface描述符为endpoint为2,bInterfaceClass为255,bInterfaceSubClass为66,bInterfaceProtocol为1。当查找到adb接口的时候,遍历endpoint描述符,由于usb3.0 endpoint描述符后面会增加usb超高速伙伴描述符,且sizeof()=6,所以usb3.0需要在找到endpoint描述符后将指针偏移+6,USB2.0则不需要。具体的描述符解释请参考usb规范。
在这里插入图片描述
查找到adb interface后再调用驱动接口注册驱动。
在这里插入图片描述
自此adb server与usb驱动的绑定就完成了。

2.5 关键log解读

当执行adb devices的时候,adb log打印endpoints not found,对应代码如下图:
在这里插入图片描述
如下图的interface descriptor配置为对应的interface为adb设备的interface:
在这里插入图片描述
adb端口对应的usb interface有两个endpoint,ep5和ep89。对应的bInterfaceClass为255,bInterfaceSubClass为66,bInterfaceProtocol为1。adb设备在插入到主机后通过读取主机侧USB设备的descriptor找到对应的interface,其查找的条件满足以上4个条件即认为找到正确的adb设备,否则失败。

3 问题小结

3.1 问题根因

adb代码里面find_usb_device,当adb server在读取到的usb设备描述符里面查找adb对应的interface和endpoint描述符来注册adb,由于usb3.0在设备描述符里面会加入usb高速端点伙伴描述符,而在usb2.0的设备描述符里面没有。在usb3.0的情况下adb需要在查找到每一个endpoint描述服务后,将缓冲区偏移一个高速端点伙伴描述符的长度。由于客户的adb代码没有进行这个补丁的修改,导致usb2.0在查找endpoint描述符的时候出现问题,从而导致问题出现。

3.2 解决方法

修改adb代码在Linux环境上,编译成adb二进制文件,进一步验证,问题不再复现。

3.3 小结

确认ep个数为2,bInterfaceClass为255,bInterfaceSubClass为66,bInterfaceProtocol为1,即可确定usb驱动和模块adb端口是没有问题的,问题一定出现在主机侧。具体的主机侧问题或者adb工具问题根据实际情况分析。


http://www.ppmy.cn/news/131465.html

相关文章

STM32F750成功运行Linux

论坛发帖太分散了,在此记录一下我开发STM32F750 uClinux开发板的进程,这是第一篇,发表于2018年12月。 前段时间ST推出了Value Line的STM32F750和H750两个系列,看了一下选型表,F750有LQFP144封装,正好适合我…

【BK3633】规格书

目录: 1. 资源预览1.1 特性1.2 引脚 2 功能描述2.1 GPIO2.2 定时器2.2.1 PWM 定时器2.2.2 看门狗定时器和RTC定时器2.2.3 亚微秒事件定时器 2.3 ADC2.4 UART、I2C和SPI2.5 USB2.6 真随机数生成器2.7 I2S音频数字接口2.8 代码加密和系统安全2.9 到达角和离开角 3 电力…

【R】【课程笔记】06 金融波动模型

本文是课程《数据科学与金融计算》第6章的学习笔记,主要介绍GARCH类、SV类模型和高频波动模型,用于知识点总结和代码练习,Q&A为问题及解决方案。 往期回顾: 博文内容【R】【课程笔记】01 R软件基础知识数据类型、数据结构、…

matlab地心坐标系和GPS坐标系的转换

** 卑微小兰的第一篇:matlab地心坐标系和GPS坐标系的转换,emmm GPS坐标系和大地坐标系的正反变换 a6378137; f0.00669437999014;%第一偏心率平方 B40; L50; H60; Na/((1-f*(sind(B)))^0.5)%N为地心到该点的空间距离 X(NH)cosd(B)cosd(L); Y(NH)cosd(B)…

62 stm32 usb自定义hid复合设备修改实验

1.引言 最近因为项目需要,我们希望单片机既能有hid键盘功能,又能有hid设备的功能。即单片机的一个usb接口插入电脑后,电脑能识别出键盘设备和hid设备,两者同时存在的。 基于项目只是要求实现功能,故本次只是对stm32usb…

week5

systemctl get-default systemctl set-default graphical.target 由命令行模式更改为图形界面模式systemctl set-default multi-user.target 由图形界面模式更改为命令行模式 systemctl restart network.service:重启网卡 ascii vim /etc/sysconfig/network-script…

<5>第五期

七、AVA反射 1.-反射的基本概念 一般情况下,我们知道一个类,那可以通过这个类创建对象; 但是如果要求通过一个对象找到一个类,这时候反射就派上用场了。 java反射实现的核心就是Class类 java.lang包下的。 2.java反射-java C…

# Chapter 5

Chapter 5 Gradient Temporal-Difference Learning with Linear Function Approximation 本章提供了线性函数近似情况下梯度-TD算法的核心思想和理论结果。在这里,我们在Baird(1995;1999)的工作基础上,探讨了用于线性函数逼近的时差学习的真…

【C++】课节笔记及梳理总结---EP5

一、课节笔记 第四章 函数与预处理 Ⅰ、概述 1.模块化程序设计   (1)基本思想:将一个大程序按照功能分割成若干个小模块   (2)开发方法:自上而下,逐步分解,分而治之  2.※ C 是模块化程序设计语言 ※ Ⅱ、定义函数的一般形式…

USB Composite 组合设备之多路CDC实现

USB Composite 组合设备之多路CDC实现 USB复合设备与组合设备区别效果展示修改相关配置修改配置项修改设备描述符修改配置、接口、端点描述符接口修改FIFO配置 知识点FIFO分配 注意事项 USB复合设备与组合设备区别 其实多个接口组合在一起有2种情况 第一种叫做USB复合设备&…

Ep5 线性模型with Pytorch

1、流程 确定数据集、 设计模型(算出预测值)、 构建损失函数(最终为一个标量值,只有标量才能用backward)和优化器、 训练周期(forward算loss,backward算grad,update更新wi) 2、numpy的广播…

HBase Shell 常用命令练习

HBase Shell 常用命令练习 前言一、HBase Shell是什么?二、HBase Shell使用步骤1.启动HBase2.启用HBase Shell3.键入HBase Shell命令操作HBase 三、常用HBase Shell实例1.常用的HBase Shell命令2.一个运用上述命令的综合实例: 总结 前言 提示&#xff1…

侃侃算法EP5·二叉树及其遍历

1. 前言 这个板块旨在记录一些日常中或是面试中会问到的算法和数据结构相关的内容,更多是给自己总结和需要的人分享。在内容部分可能由于我的阅历和实战经历不足,会有忽视或是写错的点,还望轻喷。 2. 内容 关于什么是树、子树、根节点、叶…

ES6、ES7、ES8、ES9、ES10新特性及其兼容性

强烈推荐阅读一篇文章,也是自己为了做保存把地址贴到自己博客,大家一起学习: ECMAScript 6 入门教程——阮一峰 盘点ES7、ES8、ES9、ES10新特性

es_01

字段:等于一个属性 文档:行数据等于多个字段组成 映射:mapping表结构 索引:index 数据库 存文档 类型:忽略 正排索引: 需要按照key来搜索每个key下的value,要收到全部的数据,就要进…

es(八)

单字符串串多字段查询:Dis Max Query 想在百度搜索一个单字符 should是如何算分过程 查询 should 语句句中的两个查询加和两个查询的评分乘以匹配语句句的总数除以所有语句句的总数

JS高级+ES678

js高级 数据类型 基本(值)类型 Number: 任意数值String: 任意文本Boolean: true/falseundefined: undefinednull: null 对象(引用)类型 Object: 任意对象 主要用来包含无序复杂的数据Array: 特别的对象类型(下标/内部数据有序)Function: 特别的对象类型(可执行),F…

阿里云ECS部署ES

背景 最近越来越多的公司把业务搬迁到云上,公司也有这个计划,自己抽时间在阿里云和Azure上做了一些小的尝试,现在把阿里云上部署ES和kibana记录下来。为以后做一个参考,也希望对其他人有帮助。 这里以阿里云为例,由于测…

ES-08-ElasticSearch数据分片(shard)

说明 ElasticSearch数据分片(shard)创建多分片索引、更改多分片索引副本分片数量、路由计算和分片控制官方文档:https://www.elastic.co/cn/ 核心概念 》什么是数据分片(shard)? 一个分片是一个底层的工…

ES-09-ElasticSearch分词器

说明 ElasticSearch分词器默认分词器(标准分词器)、ik分词器、ik分词器扩展字典自定义词语关键词:keyword、text、ik_max_word、ik_smart、词条、词典、倒排表官方文档:https://www.elastic.co/cn/ik分词器文档:https…
最新文章