Linux下使用USB模拟ACM串口设备
这个想法之前就在脑袋里有过,最近公司产品要用到,所以多做了些了解。
1. USB 简介
USB 是 Universal Serial Bus 的缩写,从字面上看,就是通用串行总线的意思。从物理上看,其实就是一对差分线,连接两台设备后,相互间进行数据传输。加上另外两路供电( 5V 和 GND)线,一共是 4 根线。
那么,既然是只有一对差分线,那么该如何决定由谁传给谁呢(如果两边同时在线上建立电平,线路上的电平会是不确定态的,以致无法通信)?这就要说到 USB 传输的一个重要基础:“询问-应答” 机制—— Device(slave) 设备通常是处在等待状态,只有 HOST 侧设备发起询问、请求,它才会在接下来的时间片中使用数据线向 HOST 发送数据。
那么,谁是 HOST,谁是 SLAVE 又是由什么来决定的呢?答案是硬件。也就是说,你 USB 后面的那块驱动芯片如果是 HOST,那么,这个 USB 只能做 HOST 用了。反之,SLAVE 亦然。比如我们经常见到的,PC 上的 USB HOST 连接到 U盘、鼠标、键盘这些 SLAVE 设备。
后来有人觉得这样一个设备只能是 HOST 或者只能是 SLAVE 太死板了,所以又发明了 USB OTG。USB OTG(on-the-go,大意为在使用时切换身份)是在原来 4 根线的基础上,又加了一根线,ID。那块 USB 后面的驱动芯片,就可以根据这根线,来选择自己到底该扮演 HOST 还是 SLAVE 的角色。后面我们单独介绍。
另外,因为使用一对差分线进行数据传输,所以,USB 又采用了基于 HUB 的星形拓扑结构(包括根控制器,最多7 层拓扑,且7层已不具备挂载 HUB 能力,只能是功能设备)。所以,更确切来说,“HOST-SLAVE“ 是在由 HUB 支持的物理链路之上的传输机制。同时,HUB 本身也是一个 USB SLAVE 设备。

2. USB 连接过程概述
下图很好的解释了 USB 的连接过程。需注意,1)如上图的拓扑结构所示,每个网络内只能有一个 HOST。2) HOST 和 SLAVE 之间,可以一对一直连,也可以通过 HUB ,一个 HOST 对应多个 SLAVE。

基本状态包括:设备插入、设备上电、设备复位、设备获得地址、设备配置完成、挂起状态。下面略做解释。
设备插入:HOST 侧(可能是在 HUB 上,也可能是直接在 host controller 上)根据 D+ 和 D- 口的阻抗变化,来判断是否有 device 插入,以及判断插入设备的速度类型。
设备上电:因为 USB 口有供电功能(5V DC,多为 500-1000 mA ),所以,设备又分为 Bus powered 和 self powerd。当然,即使是设备自己供电,我们也认为只有当设备已连接,它才进入powered 状态。设备一旦重新上电,后面的连接操作要重新执行一次。
设备复位:因为只有一对差分线,如果两边同时操作,那线路上的电平将是不确定态,根本无法通信。所以,上电后,USB device(slave)默认为等待状态,不进行任何动作,直到 HOST 发给它一个 Reset 请求。复位完成,意味着低速/全速/高速的物理通路已经建立。
设备获得地址:设备复位成功后,将获得一个由 HOST 分配的地址。分配地址的对话,将在设备的 endpoint0 上完成。
设备配置完成:握手?配置?反正这一阶段完成,意味着设备已经 ready了。
挂起状态:所有 USB Device(slave)在空闲一段时间后,都必须将自己挂起,并保持自己的状态,无论设备已经被分配地址还是没有分配地址。
3. OTG
OTG 增加了一根可以动态配置为 HOST 或者 DEVICE(slave)的数据线,以 micro USB 接头为例,其引脚分配如下:

因为传统的 USB 线缆为 4 根线,所以,要将 OTG 设备接入,需对其进行配置(硬件短接):
1. 当配置 OTG 设备为 USB Device(slave) 时,将 ID 脚悬空。
2. 当配置 OTG 设备为 USB HOST时,将 ID 脚接地。
所以,我们这里,需要将OTG脚悬空,来将其配置为 Slave 设备。硬件上面,买来的 OTG 转接线默认把 OTG USB 设备设置为 HOST,他们 ID 脚都是接地的。而我们是需要把 OTG 设备当作 Device(slave)来用,所以,最终选择了将板子上的 ID 线割断,使其悬空。
4. 一般的实现结构
前面我们讨论了硬件部分,同时,作为通讯接口,不可能不需要系统及软件层面的协作。先给出一张比较常见的 USB 通讯模型图,然后我们再做解释:

对于整个 USB 通讯过程,我们可以粗略的将其分为“总线层”、“功能层”和“设备层”三个层次。这三个层次的划分,主要是为了问题的集中解决。其中:
a. 总线层负责解决“点到点”的问题,主要是保障上一层可以和相邻的端点“对话”,一般还会提供硬件 buffer 公上层使用;
b. 设备层才有了设备的概念,HOST 通过 Device(Slave)的 Endpoint0 对其进行配置,准备好数据管道给上一层使用;
c. 功能层在是 Device(Slave)功能的具体实现,才能看到一个个“鲜活”的设备,才是我们看得到的 U盘、鼠标这些设备。
以某安装 Linux 的 PC 为例,作为 HOST,其中这三部分工作分别由控制器(如 EHCI 、UHCI 、OHCI),USB CORE (对前面控制器的内核支持、设备管理功能等)和 USB 上层驱动(usbmouse、usbkbd、usb-storge)。
我们要实现的 USB 串口,就是属于 USB 上层驱动部分的实现。只不过,我们是通过类似于这里 HOST 的结构,实现了一个 Device(Slave)。
5. g_serial.ko
当前内核 3.0.8 支持 Gadget Serial 接口。也就是说,如果我们有一个硬件的 USB SLAVE(可以是由 OTG 支持的), 这一驱动可以支持我们实现一个软件的 USB 串口;就像由 PL2303 或者 HM340 硬件实现的 USB Serial 一样。 只有 HOST 控制器是不行的。不管是对 HOST 侧的PC,还是我们添加 Gadget Serial 驱动支持的 PC,这条链路看起来都只是一个普通的串口连接。其源代码在 /drivers/usb/gadget/serial.c,另外还有文档 Documentation/usb/gadget_serial.txt。可自行阅读。(其实,谷歌的 ADB 工具和这个是差不多的东西,可能甚至只有驱动号不一样。)
具体应用时,我们并不需要做太多修改。。。只需要配置,编译就足够了。我把它编译成了 module,所以,需要在文件系统起来之后再做一次 modprobe。
至于 HOST 侧,据说是都不需要驱动的,但是,我在 Windows 上用的时候,还是安装了 gadget serial v2.4 的(据说不支持 64 位系统,未验证),UBUNTU 上即插即用。
Linux下使用USB模拟ACM串口设备的更多相关文章
- Linux下使用USB模拟ACM串口设备【转】
本文转载自:https://www.cnblogs.com/pied/p/4549614.html 这个想法之前就在脑袋里有过,最近公司产品要用到,所以多做了些了解. 1. USB 简介 USB 是 ...
- 【转载】linux下的usb抓包方法
1 linux下的usb抓包方法 1.配置内核使能usb monitor: make menuconfig Device Drivers --> ...
- linux下的usb抓包方法
1 linux下的usb抓包方法1.配置内核使能usb monitor: make menuconfig Device Drivers --> ...
- linux下的usb转串口的使用(修改)【转】
环境:Ubuntu 10.10 Server minicom是linux下串口通信的软件,它的使用完全依靠键盘的操作,虽然没有“超级终端”那么易用,但是使用习惯之后读者将会体会到它的高效与便利,下面将 ...
- Linux下查看USB设备的VID、PID命令
Linux下查看PID命令 cat /proc/bus/usb/devices 或 lsusb 方法一:在/etc/init.d/rcS中添加mount -t usbfs none /proc/bus ...
- linux下php pcntl_fork模拟多线程
开始用php写后台服务一段时间了.也是在这样的驱动下,不断的学习php语法,体验这一原来一直以为神秘且敬而远之的神奇语言的魅力.最初看php多线程的资料是为了提高程序的处理能力,充分发挥linux多任 ...
- Linux下的USB总线驱动(一)
版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127 一.USB理论 1. USB概念概述 USB1.0版本速度1.5Mbps(低速USB) USB1 ...
- linux下的usb抓包方法【转】
转自:http://blog.chinaunix.net/uid-11848011-id-4508834.html 1.配置内核使能usb monitor: make menuconfig ...
- Linux下查看USB设备信息
首先需要将usbfs挂载一下,然后才能查看.$ mount -t usbfs none /proc/bus/usb$ cat /proc/bus/usb/devices或者在文件(/etc/fsta ...
随机推荐
- TRIGGER command denied to user 'root'@'LAPTOP-M7KUFN86' for table 'growtest' | Table 'MyDatabase.tmpIdentity_Invites' doesn't exist
是因为创建表的时候,用户权限不够 NaviCat for Mysql 用这个工具打开MYSQL 在用户 下找到 root@% 这个用户,双击打开 设置服务器权限,最后两个权限勾上就OK 了,需要把MY ...
- FineUI小技巧(2)将表单内全部字段禁用、只读、设置无效标识
需求描述 对表单内的所有字段进行操作也是常见需求,这些操作有: 禁用:表单字段变灰,不响应用户动作. 只读:表单字段不变灰,但不接受用户输入(实际上是设置DOM节点的readonly属性),有触发器的 ...
- Webwork 学习之路【01】Webwork与 Struct 的前世今生
Struts 1是全世界第一个发布的MVC框架,它由Craig McClanahan在2001年发布,该框架一经推出,就得到了世界上Java Web开发者的拥护,经过长达6年时间的锤炼,Struts ...
- async 更优雅异步体验
上一篇<让 Generator 自启动>介绍了通过起动器让 Generator 跑起来,而本篇采用 async 实现更优雅的异步编程. 从例子开始 借用上一篇例子中的例子说起. funct ...
- ffmpeg在shell循环中只执行一次问题
最近写了一个shell脚本,发现 ffmpeg 命令只执行了一次就停了,最后找到原因: ffmpeg有时会读取标准输入流,导致命令出错,解决办法是在ffmpeg命令之后添加 #xxx ffmpeg x ...
- 《深入理解Spark:核心思想与源码分析》(前言及第1章)
自己牺牲了7个月的周末和下班空闲时间,通过研究Spark源码和原理,总结整理的<深入理解Spark:核心思想与源码分析>一书现在已经正式出版上市,目前亚马逊.京东.当当.天猫等网站均有销售 ...
- 如何采集QQ群中所有成员QQ号码
安装Google Chrome浏览器 安装Google插件:Regex Scraper 在群成员页面点击Regex 插件, 粘贴上这个代码 text_overflow">([\S\s] ...
- j-link或者swd调试
两种 一.JTAG调试(5针), 二.SWD调试(2针), 在JTAG/SWD模式设置库函数 (在文件stm32f10x_gpio.c中): void GPIO_PinRemapConfig(uint ...
- matlab画图形函数 semilogx
matlab画图形函数 semilogx loglog 主要是学习semilogx函数,其中常用的是semilogy函数,即后标为x的是在x轴取对数,为y的是y轴坐标取对数.loglog是x y轴都取 ...
- 取消Git代理设置
昨天由于在用sourceTree上传下拉代码的时候,速度实在太慢,就照着百度上的方法设置了代理,结果导致sourceTree无法访问服务器,经检查排除发现可能是因为公司网络不能使用代理,被防火墙挡住了 ...