当前位置: 首页 > news >正文

usb 串行口驱动庖丁解牛4: 数据收发的实现


author: hjjdebug
date: 2026年 05月 17日 星期日 15:47:42 CST
descrip: usb 串行口驱动庖丁解牛4: 数据收发的实现


文章目录

  • 1. 数据收发的过程:
  • 2. 代码说明
  • 3.代码:
  • 4. 测试.

1. 数据收发的过程:

open/close 端口
批量 OUT 端点 发送数据
批量 IN 端点 接受数据
内核串口层自动向上层 tty 提交收到的数据

2. 代码说明

.open 和 .close
使用默认的 usb_serial_generic_open 和 usb_serial_generic_close。
.read 和.write
使用默认的 usb_serial_generic_read 和 usb_serial_generic_write。
波特率设置, 也走默认函数.
pl2303驱动就没干啥事!!
为啥? 因为都是底层给干完了.
它只是干了自己底层不能干,必需自己干的事.
定义id匹配表,定义资源,返回接口个数.
这就是pl2303 的三线驱动(Rxd,Snd,Gnd)的最简代码, 40行代码而完整版1千多行代码.
理解这40行代码,才是精髓. 怪不得1000行代码不易看懂,因为不对应核心意义.
差不多是废代码,冗余代码. 一大堆啰里扒嗦代码,把本质都掩盖了.
其实,pl2303就是没干什么事, 核心工作都是usb_serial 子系统干的.
如果你想在驱动中干点事情, 那就拦截usb_serial 子系统.

3.代码:

对于pl2303 驱动, 3线通讯模式(主机跟嵌入式通讯的方式), 带流控不太清楚(没有测试)
这40行代码足以替代厂家的1079行代码

$ cat pl2303.c#include<linux/module.h>#include<linux/tty.h>#include<linux/usb.h>#include<linux/usb/serial.h>#definePL2303_VID0x067B#definePL2303_PID0x2303staticconststructusb_device_idid_table[]={{USB_DEVICE(PL2303_VID,PL2303_PID)},{}};MODULE_DEVICE_TABLE(usb,id_table);staticintpl2303_calc_num_ports(structusb_serial*serial,structusb_serial_endpoints*ep){return1;//这里返回有一个接口, 系统会创建出/dev/ttyUSB0 一个节点}staticstructusb_serial_driverpl2303_minimal={.driver={.owner=THIS_MODULE,.name="pl2303_minimal",},.id_table=id_table,.num_bulk_in=1,//设备可能有很多端点,但驱动可以不用,所以这里要配置.num_bulk_out=1,//驱动向内核报资源,它可以在这里插一手..num_interrupt_in=0,.calc_num_ports=pl2303_calc_num_ports,};staticstructusb_serial_driver*constserial_drivers[]={&pl2303_minimal,NULL};module_usb_serial_driver(serial_drivers,id_table);MODULE_LICENSE("GPL");

4. 测试.

删除原有驱动 rmmod pl2303
安装新编译驱动. insmod pl2303.ko
测试串口收发完全正常.
用自编的窗口应用程序精准控制测试.
程序可参考:彻底搞懂搞定终端设置

(用echo, cat , stty 也可以)

$ ./serial_recv
接收端已启动,设备: /dev/ttyUSB0,波特率: 115200
按 Ctrl+C 退出
第 1 次接收: 长度: 1 字节 | HEX: 68 | ASCII: h
第 2 次接收: 长度: 1 字节 | HEX: 65 | ASCII: e
第 3 次接收: 长度: 1 字节 | HEX: 6C | ASCII: l
第 4 次接收: 长度: 1 字节 | HEX: 6C | ASCII: l
第 5 次接收: 长度: 1 字节 | HEX: 6F | ASCII: o
第 6 次接收: 长度: 1 字节 | HEX: 20 | ASCII:
第 7 次接收: 长度: 1 字节 | HEX: 77 | ASCII: w
第 8 次接收: 长度: 1 字节 | HEX: 6F | ASCII: o
第 9 次接收: 长度: 1 字节 | HEX: 72 | ASCII: r
第 10 次接收: 长度: 1 字节 | HEX: 6C | ASCII: l
第 11 次接收: 长度: 1 字节 | HEX: 64 | ASCII: d
第 12 次接收: 长度: 1 字节 | HEX: 0A | ASCII: \n
$ ./serial_send
准备发送字符串(共 12 字节):hello world
发送次数:1
第 1 次发送,成功写入 12 字节
所有发送完成,关闭串口

那这里就要问几个问题,

  1. 为什么我没有设置open, 就走了usb_serial_generic_open
    我没有在驱动中设置.write, 就调用了usb_serial_generic_write.
    usb_serial.c 与 pl2303.c 到底是什么关系?
    怎样实现的这种继承,补充,拦截关系?

答:
pl2303 注册驱动的时候, 里面有一个对应的驱动对象,是usb_serial 创建的,
各函数指针已经有值了, 现在,pl2303如果有值,会覆盖原有值. 以后调用,就会走到pl2303函数
如果pl2303 没有值,就不会覆盖旧值,还走以前的老路
所以pl2303 只是一个锦上添花的事情, 大部分别人都准备好了.

  1. write 容易理解, 一路调用下去,最后通过URB 控制块,通过USB总线把数据发送给设备.
    我们read 的时候, 数据是怎么上来的? 会阻塞吗?

答: read 的时候,我们读得是缓存中的数据, 如果缓存有数据,就直接给上层. 有多少返回多少.
没有数据,会阻塞, 如果超过等待时间,就返回0字节. 需要等上层再次调用read.
那缓存中的数据是怎么来的?
缓存中的数据是usb控制器不断的发送bulk_in 指令获取到的. usb 控制器是个硬件,它不断的询问
设备,有数据吗? 有数据就上. 控制器一但启动,通过usb总线上数的过程是不需要程序参与的.
usb控制器为啥这样工作呢? 因为我们驱动配置了bulk_in 为1, 系统就会命令控制器, 给我
时刻关注设备bulk_in 端点.
控制器收到了数据,就会通知系统来取数, 系统在中断服务程序中,把数据存入缓冲区.
在pl2303程序中,我们即没有看到对控制器的操控命令, 也没有看到中断服务程序
都被隐藏到底层了. 所以感觉还是看得少了点. 但是,流程倒是想清楚了.

自此,估计所谓的ch341 驱动, cp210x 驱动, 标准acm(抽象控制模型)等驱动,估计也都能用几行代码搞定.
因为usb-serial核心框架已经有了,再加点小补充,适配自己的ID, 说不定读,写,控制都是标准协议.
至于那些modem 信号控制, 本人这里没有环境, 主要还是根本就没有使用过, 可能各驱动需要单独写吧.
不过我就不关心了.因为几乎用不到.

以后几年前买的这个usb转串口线,就用我的40行代码小驱动了. 因为我了解了它的工作原理.
我写了4篇博客想搞通usb转串口详细的工作原理,到最后收获了40行代码,整了个寂寞,深入浅出啊,这是1000行代码中过滤的.

http://www.jsqmd.com/news/838335/

相关文章:

  • MOOTDX:解锁量化投资的免费通达信数据接口,5分钟构建专业金融数据平台
  • Kubernetes轻量级服务网格Cetus:核心流量治理与Sidecar代理实践
  • 圣多美投资入籍项目评选标准权威发布:睿港国际移民真正符合金字塔顶端的严苛要求! - 博客万
  • AI智能体沙盒环境AgentBox:安全隔离与容器化部署实践
  • MySQL 库的操作
  • 从蓝牙4.2到5.4:广播包格式的‘进化史’与向后兼容那些坑
  • AChat开源项目:快速构建本地大模型Web聊天界面的轻量级脚手架
  • 5分钟掌握猫抓扩展:浏览器视频下载终极指南
  • 暗黑破坏神2存档编辑器完整指南:如何5分钟内打造你的完美角色
  • 基于Go与Croc构建Telegram文件传输机器人:原理、部署与优化
  • XHS-Downloader:小红书内容批量下载终极指南
  • OrigamiSimulator:从平面到立体的折纸魔法,让想象力自由飞翔的终极指南
  • GPT5.5合同要点提炼:责任方、时间节点、违约条款抽取
  • 别再手动调色了!用Matlab bar3函数+addcolorplus,5分钟搞定论文级渐变三维柱状图
  • 如何将AI 3D模型生成工具集成到你的开发工作流
  • 别再死记硬背真值表了!用Verilog手搓半减器/全减器,从波形图反推逻辑门设计
  • 哔咔漫画下载器终极指南:3步搞定个人离线漫画库
  • Codesys标签通讯实战:三步搞定昆仑屏数据交互
  • NotebookLM权限配置必须在24小时内完成的4项关键校验(附自动化checklist+curl一键验证脚本)
  • 扣图操作方法全攻略:从入门到精通,一文掌握AI抠图技巧
  • 终极指南:如何用FanControl实现Windows系统风扇智能控制
  • LAMMPS效率翻倍秘籍:从单机到并行,你的MPICH配置真的对了吗?
  • 各种遍历算法之二叉树的最大深度
  • ComfyUI ControlNet Aux终极指南:30+预处理节点完全解析与快速部署方案
  • 告别手动!用Allegro Testprep脚本批量处理测试点,效率提升200%
  • 5.17 赵文奇
  • 2026 年视频生成模型横评:Seedance 2.0 vs Sora 2 Pro vs Kling 3.0 深度解析与实测教程
  • Java17/21实战|用模式匹配干掉90%的if-else和强制转换,代码瞬间优雅!
  • 在西安莲湖区看牙的真实体验记录
  • 北京改灯认准这家!LED / 激光透镜专业升级,亮度翻倍 - 北京波波