1. 硬件体验
使用 Linux 自带的 USB Gadget 驱动 /drivers/usb/gadget/legacy/serial.c
使用 USB 线,连接板子的 OTG 口和 PC 的 USB 口。
然后在板子加载驱动程序后,可以看到新的设备节点 /dev/ttyGS0:
# modprobe g_serial
g_serial gadget: Gadget Serial v2.4
g_serial gadget: g_serial ready
g_serial gadget: high-speed config #2: CDC ACM config
# ls /dev/ttyGS0 -l
crw-rw---- 1 root dialout 246, 0 Jan 1 00:30 /dev/ttyGS0
在 PC 上,如果是 Windows 系统,可以在设备管理器里看到新的 USB 串口:
在 PC 上,如果是 VMware 上的 Linux 系统,按下图操作,先把 USB 串口连接到 VMware:
然后在 PC Linux 中可以看到新的设备节点:
book@100ask:~$ dmesg
[ 286.903239] usb 1-1: new high-speed USB device number 2 using ehci-pci
[ 287.254549] usb 1-1: New USB device found, idVendor=0525, idProduct=a4a7, bcdDevice= 4.09
[ 287.254550] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 287.254551] usb 1-1: Product: Gadget Serial v2.4
[ 287.254552] usb 1-1: Manufacturer: Linux 4.9.88 with 2184000.usb
[ 287.342786] cdc_acm 1-1:2.0: ttyACM0: USB ACM device
[ 287.343202] usbcore: registered new interface driver cdc_acm
[ 287.343202] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
book@100ask:~$ ls /dev/ttyACM0 -l
crw-rw---- 1 root dialout 166, 0 Mar 5 22:38 /dev/ttyACM0
2. Serial分析
2.1 软件框架
Gadget 串口的框架如下:
u_serial 提供了有 2 种方法来使用 Gadget 串口:
- u_serial.c 里注册 tty_driver 结构体 gs_tty_driver,在板子上编写 APP 访问设备 /dev/ttyGS0 即可与 Host 交互(Host 要打开 USB 串口)
- u_serial.c 里注册 console 结构体 gserial_cons。启动 Linux 内核时传入 commandline 参数"console=ttyGS0"后,内核的 printk 的信息通过 Gadget 串口打印出来(Host 要打开 USB 串口):
注册 TTY 和 console 的过程:
gs_bind // driversusbgadgetlegacyserial.c
status = serial_register_ports(cdev, &serial_config_driver,"acm");
fi_serial[i] = usb_get_function_instance(f_name);
acm_alloc_instance // driversusbgadgetfunctionf_acm.c
ret = gserial_alloc_line(&opts- >port_num); // driversusbgadgetfunctionu_serial.c
// 注册TTY
tty_dev = tty_port_register_device(&ports[port_num].port- >port,
gs_tty_driver, port_num, NULL);
// 注册console
gserial_console_init();
register_console(&gserial_cons);
2.2 数据传输
2.2.1 APP 访问
注意,在 USB 中数据传输总是由 Host 发起,所以:
- 板子要事先准备好空间(设置好 out 方向的 usb_request 并放入队列),以便接收 Host 发来的数据;
- 板子有数据想发送给 Host 时需要设置 in 方向的 usb_request,以便 Host 读取。
板子上的 APP 访问 /dev/ttyGS0 时,就会导致 gs_tty_ops 结构体的对应函数被调用:
APP 调用 open 函数时,会导致如下调用:
gs_open
gs_start_io(port);
// 取出 out 端点(对应 Host 来说是 out, 对于板子来说就是输入)
struct usb_ep *ep = port- >port_usb- >out;
// 给 out 端点分配 usb_request
status = gs_alloc_requests(ep, head, gs_read_complete,&port- >read_allocated);
// 给 in 端点分配 usb_request, 但是在 open 时并没有把 in 方向的 usb_request 放入队列
status = gs_alloc_requests(port- >port_usb- >in, &port- >write_pool,gs_write_complete, &port- >write_allocated);
// 把 usb_request 放入队列, 如果 Host 发来数据, 这个 usb_request 的 complete 函数被调用
started = gs_start_rx(port);
status = usb_ep_queue(out, req, GFP_ATOMIC);
APP 调用 write 函数时,会导致如下调用:
gs_write
gs_start_tx(port);
// 把 usb_request 放入队列, Host读取数据时就可以从中得到数据
status = usb_ep_queue(in, req, GFP_ATOMIC);
2.2.2 printk
启动 Linux 内核时传入 commandline 参数"console=ttyGS0"后,内核的 printk 的信息通过 Gadget 串口打印出来(Host 要打开 USB 串口)。
内核的 printk 函数会导致 gserial_cons 结构体中的 write 指针即gs_console_write
函数被调用:
gs_console_write 函数的调用关系如下:
gs_console_write
// 把要打印的数据放入环形 buffer
gs_buf_put(&info- >con_buf, buf, count);
// 唤醒内核线程
wake_up_process(info- >console_thread);
// 内核线程
gs_console_thread
// 被唤醒后
// 取出输入端点和它的 usb_request
req = info- >console_req;
ep = port- >port_usb- >in;
// 从环形 buffer 得到数据、设置 usb_request
xfer = gs_buf_get(&info- >con_buf, req- >buf, size);
req- >length = xfer;
// 把 usb_request 放入队列,以便 Host 读取
ret = usb_ep_queue(ep, req, GFP_ATOMIC);
-
嵌入式
+关注
关注
5096文章
19199浏览量
308296 -
驱动
+关注
关注
12文章
1855浏览量
85742 -
Linux
+关注
关注
87文章
11354浏览量
210662
发布评论请先 登录
相关推荐
如何配置USB OTG为Gadget serial device?
分享一种将RK3399配置成USB gadget设备的方法
基于Linux内核的Rockchip USB Gadget UAC开发资料分享
RK3288使用USB GADGET实现大容量存储脚本
求助,关于USB gadget安装虚拟网口问题求解
PL2303 USB to Serial Adapter
Universal Serial Bus(USB) Devi
[嵌入式linux]将linux板卡虚拟为USB网卡设备(Ethernet Gadget)
![[嵌入式linux]将linux板卡虚拟为<b class='flag-5'>USB</b>网卡设备(Ethernet <b class='flag-5'>Gadget</b>)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
AMD Xilinx Linux 2022.1 USB Gadget使用
USB Gadget 应用实例ADB实现
![<b class='flag-5'>USB</b> <b class='flag-5'>Gadget</b> 应用<b class='flag-5'>实例</b>ADB实现](https://file1.elecfans.com/web2/M00/8C/A2/wKgaomSvZ7WAQt-hAAGOBaqBAZg150.jpg)
USB Gadget serial应用实例(下)
USB Gadget zero应用实例程序
![<b class='flag-5'>USB</b> <b class='flag-5'>Gadget</b> zero应用<b class='flag-5'>实例</b>程序](https://file1.elecfans.com/web2/M00/8C/A2/wKgZomSva-iADAypAAC3NHq5ZPM519.jpg)
从硬件软件角度理解Gadget框架
![从硬件软件角度理解<b class='flag-5'>Gadget</b>框架](https://file1.elecfans.com/web2/M00/8C/A3/wKgaomSvbR2AEoUiAAWGHZ-svJI275.jpg)
评论