加载usbserial驱动后,为什么adb不可用了?
某设备提供了USB串口功能,上位机(Host端)可以通过USB串口与之通信。对于Linux上位机,比如Ubuntu,自带usbserial驱动,当安装usbserial驱动后,上位机就会生成ttyUSBx(x=0~n)设备,通过ttyUSBx就能与设备端进行USB串口通信。
该设备不仅提供了USB串口,也同时提供了adb口的功能。实际应用中发现,将设备通过USB线连接到Ubuntu PC后,有生成adb口,adb能正常使用;但是串口驱动默认没有加载,手动insmod usbserial后,串口可以正常使用,但是adb口却不通了。
usbserial的使用方法可参考kernel document:Documentation/usb/usb-serial.txt
insmod usbserial vendor=0x#### product=0x####
####是vendor id和product id。
调查发现,Ubuntu加载usbserial驱动后,原来的adb口会被识别为USB串口,生成新的ttyUSBx设备,导致Ubuntu端的adb无法正常与设备端通信。从这个现象看,是Ubuntu端usbserial驱动错误地匹配了本来不应该属于它匹配的设备。具体情况如下。
成功执行adb shell后,加载usbserial驱动之前,在Ubuntu上执行 lsusb -t 指令得到的结果截取如下:
Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/10p, 480M
|__ Port 6: Dev 4, If 5, Class=Vendor Specific Class, Driver=, 480M
|__ Port 6: Dev 4, If 6, Class=Vendor Specific Class, Driver=usbfs, 480M
加载usbserial驱动之后,再次插拔USB,在Ubuntu上执行 lsusb -t 指令得到的结果截取如下:
Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/10p, 480M
|__ Port 6: Dev 4, If 5, Class=Vendor Specific Class, Driver=usbserial_generic, 480M
|__ Port 6: Dev 4, If 6, Class=Vendor Specific Class, Driver=usbserial_generic, 480M
If 5对应的是串口,If 6对应的是adb口;正常情况下,adb口匹配的驱动是usbfs ,异常情况下,adb口匹配的驱动是 usbserial_generic 。
为什么usbserial驱动会错误地匹配了本来不应该属于它匹配的设备呢?这个需要从源码码中去寻找答案(Linus名言:Read the fu*k source code ^_^)。
代码路径在 drivers/usb/serial/*,关键代码如下,从match_flags可以看出,usb generic serial驱动是简单地通过vendor id和product id来匹配设备。
drivers/usb/serial/generic.c int usb_serial_generic_register(void)
{
int retval = 0; #ifdef CONFIG_USB_SERIAL_GENERIC
generic_device_ids[0].idVendor = vendor;
generic_device_ids[0].idProduct = product;
generic_device_ids[0].match_flags =
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; retval = usb_serial_register_drivers(serial_drivers,
"usbserial_generic", generic_device_ids);
#endif
return retval;
} drivers/usb/serial/usb-serial.c static int __init usb_serial_init(void)
{
int result; usb_serial_tty_driver = alloc_tty_driver(USB_SERIAL_TTY_MINORS);
...
/* register the generic driver, if we should */
result = usb_serial_generic_register();
由于该设备的adb口和串口都是基于同样的USB设备,具有同样的vendor id和product id,那adb口被识别成串口,也就能理解了。
原因找到了,那有没有办法解决这个问题呢?
1)上位机先执行adb shell把adb口占住,再加载usbserial驱动,则adb口不会被重新匹配serial驱动;但是重新插拔USB后,又需要卸载usbserial驱动,再重复此过程。临时用用倒是可以。
2)修改usbserial驱动。在开发嵌入式产品时,一般上位机也是需要源码级开发的,在这种场景下修改usbserial驱动比较适用。
看看adb和generic串口的接口描述符信息。在Ubuntu上执行lsusb -v指令后得到的adb接口描述符如下:
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 6
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 66
bInterfaceProtocol 1
iInterface 10 ADB Interface
usb generic串口的接口描述符如下:
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 5
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
可以看到两者的 bInterfaceClass 是一样的,都是 Vendor Specific Class ,但是 bInterfaceSubClass 和 bInterfaceProtocol 不一样。所以可以考虑修改usbserial驱动的匹配规则,除了vendor id和product id之外,再加入按interface class和interface protocol联合匹配。
除了USB generic serial驱动外,还有一些厂商自定义的USB serial驱动,比如 drivers/usb/serial/option.c,该驱动就在probe函数里面设置了一些判断条件,避免匹配上不该匹配的设备,可用来参考。如下,代码注释得相当详细,不再赘述。
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
struct usb_interface_descriptor *iface_desc =
&serial->interface->cur_altsetting->desc;
unsigned long device_flags = id->driver_info; /* Never bind to the CD-Rom emulation interface */
if (iface_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE)
return -ENODEV; /*
* Don't bind reserved interfaces (like network ones) which often have
* the same class/subclass/protocol as the serial interfaces. Look at
* the Windows driver .INF files for reserved interface numbers.
*/
if (device_flags & RSVD(iface_desc->bInterfaceNumber))
return -ENODEV; /*
* Allow matching on bNumEndpoints for devices whose interface numbers
* can change (e.g. Quectel EP06).
*/
if (device_flags & NUMEP2 && iface_desc->bNumEndpoints != 2)
return -ENODEV; /* Store the device flags so we can use them during attach. */
usb_set_serial_data(serial, (void *)device_flags); return 0;
}
欢迎关注我的公众号,一起交流。微信搜索“大鱼嵌入式”或者扫描下列二维码。

加载usbserial驱动后,为什么adb不可用了?的更多相关文章
- Intel Nehalem微架构Calpella平台机型Windows XP系统下如何开启AHCI硬盘工作模式(XP系统下如何加载AHCI驱动)
问题描述用户来电表示使用IDE模式安装XP系统后开启AHCI模式会出现开机蓝屏重启的问题,咨询如何在XP下加载AHCI驱动,以便开启BIOS中AHCI选项来发挥硬盘的最佳性能 问题分析 Windo ...
- Linux中mod相关的命令 内核模块化 mod相关命令都是用来动态加载内核模块/驱动程序模块
Linux中mod相关的命令 内核模块化 mod相关命令都是用来动态加载内核模块/驱动程序模块 http://baike.baidu.com/link?url=lxiKxFvYm-UfJIxMjz ...
- 无软驱加载raid驱动安装windows2003及其他微软操作系统
[转载]http://blog.zol.com.cn/2650/article_2649199.html [另一篇]http://www.blue1000.com/bkhtml/c159/2013-0 ...
- win10系统加载ahci驱动的操作方案(Win10之家)
win10系统使用的过程中很多用户会想要加载ahci驱动,但是大部分用户根本不知道怎么操作加载ahci驱动,这样的话很多用户会遇到一些问题,那如果使用的过程中想要加载ahci驱动的话我们应该怎么操作呢 ...
- JDBC:加载数据库驱动、连接数据库(详细讲解)
加载数据库驱动: 1)由于Java是一个纯面向对象语言,任何事物在其中都必须抽象成类或者类对象,数据库也不例外,JDBC同样也把数据库抽象成面向对象的结构: 2)JDBC将整个数据库驱动器在底层抽象成 ...
- ThinkCMF项目部署出现无法加载数据库驱动解决方案
最近有个TP项目刚从从本地部署到阿里云服务器上,出现了无法加载数据库驱动的错误,提示 :( 无法加载数据库驱动: Think\Db\Driver 这里分享一下出现该错误的解决步骤: 首先记得项目部署到 ...
- java 加载数据库驱动
JDBC编程步骤见 JDBC编程步骤 JDBC编程的第一步是加载数据库驱动,使用Class类的forName()方法,Class.forName("com.mysql.jdbc.Driver ...
- java加载jdbc驱动三种方式的比较
一.引言 平时连接数据库的时候首先要加载jdbc驱动,这一步骤其实有三种方式,他们的区别?优劣? 二.快速了解三种加载方式 Class.forName(“com.mysql.jdbc.Driver”) ...
- JDBC 学习笔记(四)—— JDBC 加载数据库驱动,获取数据库连接
1. 加载数据库驱动 通常来说,JDBC 使用 Class 类的 forName() 静态方法来加载驱动,需要输入数据库驱动代表的字符串. 例如: 加载 MySQL 驱动: Class.forName ...
随机推荐
- 快速创建你的第一个Spring Boot项目
1. 创建工程 打开idea,利用Spring Boot搭建一个web工程,切身体会一下Spring Boot所带来的魅力!看看SpringBoot是如何快速搭建一个web项目. New-->P ...
- Java框架Spring Boot & 服务治理框架Dubbo & 应用容器引擎Docker 实现微服务发布
微服务系统架构实践 开发语言Java 8 框架使用Spring boot 服务治理框架Dubbo 容器部署Docker 持续集成Gitlab CI 持续部署Piplin 注册中心Zookeeper 服 ...
- Kafka 常见问题汇总
Kafka 常见问题汇总 1. Kafka 如何做到高吞吐.低延迟的呢? 这里提下 Kafka 写数据的大致方式:先写操作系统的页缓存(Page Cache),然后由操作系统自行决定何时刷到磁盘. 因 ...
- elementui 表格 如何使操作中隐藏一个按钮
<el-table-column label="权限"min-width="100"> <template scope="scope ...
- 【图像处理】OpenCV+Python图像处理入门教程(七)图像形态学操作
图像形态学主要从图像内提取分量信息,该分量信息通常对表达图像的特征具有重要意义.例如,在车牌号码识别中,能够使用形态学计算其重要特征信息,在进行识别时,只需对这些特征信息运算即可.图像形态学在目标视觉 ...
- filesort排序原理
在执行计划中,可能经常看到有Extra列有filesort,这就是使用了文件排序,这当然是不好的,应该优化,但是,了解一下他排序的原理也许很有帮助,下面看一下filesort的过程: 1.根据表的索引 ...
- vue篇之路由详解
一.vue路由传参的几种方式 1.声明式 router-link 父组件:<router-link :to="`/path/${id}`"><router-lin ...
- CrackMe_002
老规矩,先熟悉程序. 只有一个验证的功能,错误提示You Get ... 关闭没有nag窗口 第一种,暴力破解 查找字符串,很少,直接双击进入 可以看到错误提示的跳转来自: 表示这应该是个重要的跳转, ...
- Vue3+Vite引入Echarts5.0图表库
1 概述 环境Vue3+Vite,需要引入ECharts库. 2 尝试 目前ECharts已更新到5.0版本,在Vue中引入并不难,npm/cnpm安装后在需要的组件中引入: import echar ...
- python进阶(16)深入了解GIL锁(最详细)
前言 python的使用者都知道Cpython解释器有一个弊端,真正执行时同一时间只会有一个线程执行,这是由于设计者当初设计的一个缺陷,里面有个叫GIL锁的,但他到底是什么?我们只知道因为他导致pyt ...