赞
踩
目录
A. 修改 [KERNEL_SRC] /kernel/kernel-5.10/drivers/usb/serial/option.c 文件
B. 修改 [KERNEL_SRC] /kernel/kernel-5.10/drivers/usb/serial/usb_wwan.c 文件
使用Quectel移远EC200A型号的4G模块给NVIDIA® Jetson AGX Xavier™平台添加移动网络。
· NVIDIA® Jetson AGX Xavier™嵌入式平台,如图1左;
· Quectel EC200A 4G USB Dongle通信模块,如图1右。
图1 AGX平台(左)和4G模块(右)
· 系统版本:Ubuntu 20.04.5 LTS
· 编译工具:aarch64-linux-gnu-gcc 9.4.0
本文是在目标设备AGX(arm64/aarch64)上配置并编译Linux驱动,也可以在x64架构的电脑主机上采用交叉编译方式进行配置。如果采用交叉编译的方式则推荐使用的交叉编译工具链为aarch64-linux-gnu-gcc 7.3.1 (Linaro GCC 7.3-2018.05),下载地址:Linaro Releases
NVIDIA Jetson AGX系列是专为嵌入式人工智能应用而设计的开发板,它具有自己特定的硬件架构和外设。为了适配硬件平台,我们不能使用普通的kernel内核源码。
根据AGX的Linux内核版本,在NVIDIA官网下载对应的Linux内核源码。
- mv@ubuntu:~$ uname -a
- Linux ubuntu 5.10.104-tegra #1 SMP PREEMPT Sun Mar 19 07:55:28 PDT 2023 aarch64 aarch64 aarch64 GNU/Linux
- mv@ubuntu:~$ head -n 1 /etc/nv_tegra_release
- # R35 (release), REVISION: 3.1, GCID: 32827747, BOARD: t186ref, EABI: aarch64, DATE: Sun Mar 19 15:19:21 UTC 2023
这里使用的AGX版本是R35,内核版本是Linux 5.10.104。于是在NVIDIA DEVELOPER下载中心(需要注意的是NVIDIA开发者的.cn网站不提供下载页面,访问后提示找不到页面,这里给出的是NVIDIA开发者.com的网站:Jetson Download Center | NVIDIA Developer)搜索kernel,并选择对应的版本(R35.1),如图2所示。点击下载跳转到对应的下载页面,如图3所示。
图2 Jetson Download Center页面
图3 Jetson Linux 35.1页面
现在NVIDIA产品套件的源码是打包在一起的,也就是图3中对应的红框部分Driver Package (BSP) Sources。这里我们也可以使用NVIDIA提供的交叉编译工具链aarch64-buildroot-linux-gnu-gcc 9.3(如图3中橙色线框,Bootlin Toolchain gcc 9.3)进行交叉编译。
下载图3中对应的红框部分Driver Package (BSP) Sources后得到public_sources.tbz2。在[DECOMPRESS_OUT] /Linux_for_Tegra/source/public/ 文件夹内找到kernel_src.tbz2,这就是AGX所使用kernel内核源码文件。将内核源码解压到普通用户目录下的某个文件夹内,便于后续添加USB驱动代码,内核源码解压后的文件如图4所示。
图4 kernel内核源码解压文件目录
图4中显示的内核源码解压文件,后续我们主要会使用其中的 [KERNEL_SRC] /kernel/kernel-5.10/ 这个文件夹及其内的源文件。
Quectel EC200A_CN型号的4G模块只需用到USB接口,没有使用RJ45(8P8C)网络接口。于是仅需配置EC200A在Linux系统下的USB驱动即可,无需配置GobiNet驱动和QMI驱动。因为GobiNet驱动和QMI驱动是与网卡相关的驱动。因此,这里我们主要移植4G模块在Linux系统下的USB驱动。
参考Quectel官方提供的《Quectel LTE&5G Linux USB Driver User Guide V2.0.pdf》文件配置USB驱动。
将4G模块的USB口连接到AGX上,在AGX平台使用命令行 lsusb 查询当前设备中所有的USB信息,如下图5所示。从图5中,我们可以看到EC200A模块的 [VID:PID] 为 [2C7C:6005] 。
图5 查询4G模块USB信息
在option.c文件中的static const struct usb_device_id option_ids[] 中添加设备的VID和PID,如图所示6。
- static const struct usb_device_id option_ids[] = {
-
- /****************** Added by Helmholtz_optic *************************/
-
- { USB_DEVICE(0x2C7C, 0x6005) },/* Quectel EC200A: add VID and PID */
-
- /******************************************************************************/
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) },
- { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
-
- ......
-
- }
图6 添加VID和PID
在option.c文件中的static struct usb_serial_driver option_1port_device 中添加掉电恢复机制,如图7所示。
- static struct usb_serial_driver option_1port_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "option1",
- },
- .description = "GSM modem (1-port)",
- .id_table = option_ids,
- .num_ports = 1,
- .probe = option_probe,
- .open = usb_wwan_open,
- .close = usb_wwan_close,
- .dtr_rts = usb_wwan_dtr_rts,
- .write = usb_wwan_write,
- .write_room = usb_wwan_write_room,
- .chars_in_buffer = usb_wwan_chars_in_buffer,
- .tiocmget = usb_wwan_tiocmget,
- .tiocmset = usb_wwan_tiocmset,
- .get_serial = usb_wwan_get_serial_info,
- .set_serial = usb_wwan_set_serial_info,
- .attach = option_attach,
- .release = option_release,
- .port_probe = usb_wwan_port_probe,
- .port_remove = usb_wwan_port_remove,
- .read_int_callback = option_instat_callback,
- #ifdef CONFIG_PM
- .suspend = usb_wwan_suspend,
- .resume = usb_wwan_resume,
-
- /****************** Added by Helmholtz_optic *************************/
-
- .reset_resume = usb_wwan_resume, /*Quectel EC200A: add reset resume*/
-
- /******************************************************************************/
-
- #endif
- };
图7 添加掉电恢复机制
在usb_wwan.c文件中的static struct urb *usb_wwan_setup_urb() 中添加休眠唤醒机制,如图8所示。
- static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
- int endpoint,
- int dir, void *ctx, char *buf, int len,
- void (*callback) (struct urb *))
- {
- struct usb_serial *serial = port->serial;
- struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
- struct urb *urb;
-
- urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
- if (!urb)
- return NULL;
-
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev, endpoint) | dir,
- buf, len, callback, ctx);
-
- if (intfdata->use_zlp && dir == USB_DIR_OUT)
- urb->transfer_flags |= URB_ZERO_PACKET;
-
- /****************** Added by Helmholtz_optic *************************/
-
- /*Quectel 2C7C modules: add the zero packet mechanism*/
- if(dir == USB_DIR_OUT){
- struct usb_device_descriptor *desc = &serial->dev->descriptor;
- if(desc->idVendor == cpu_to_le16(0x2c7c))
- urb->transfer_flags |= URB_ZERO_PACKET;
- }
-
- /******************************************************************************/
-
- return urb;
- }
图8 添加零包机制
进入并在 [KERNEL_SRC] /kernel/kernel-5.10/ 目录下进行内核编译。
- $mkdir ../../kernel_out
- $TEGRA_KERNEL_OUT=../../kernel_out
- $export CROSS_COMPILE=aarch64-linux-gnu-
在 [KERNEL_SRC] / 目录下建立了名为 kernel_out 的编译输出文件夹,并导入编译工具链。
接着配置编译选项,如下:
$sudo make ARCH=arm64 O=$TEGRA_KERNEL_OUT menuconfig
在弹出的menuconfig中配置编译输出选项,这里推荐将USB驱动编译成模块(m),便于移植和加载。
- [ ] Device Drivers →
- [*] USB Support →
- [M] USB Serial Converter support →
- [M] USB driver for GSM and CDMA modems
需要注意的是,按照Quectel官方提供的《Quectel LTE&5G Linux USB Driver User Guide V2.0.pdf》中的menuconfig设置后,无法生成独立的.ko文件。它的做法是将驱动模块文件编译进Linux内核中(y),而不是模块化(m)编译生成独立的驱动模块文件(.ko文件)。
最后就可以编译内核了,这里使用的AGX的CPU核心数为8。
$sudo make ARCH=arm64 O=$TEGRA_KERNEL_OUT -j8
成功编译完成后,有如下输出显示,如图9所示。
图9 成功编译输出
在编译输出的kernel_out文件夹中,[kernel_out] /drivers/usb/serial/ 文件夹中找到生成的option.ko,usb_wwan.ko 和 qcserial.ko 文件,并将这些文件复制到AGX的驱动文件夹中。
- $sudo cp option.ko /usr/lib/modules/5.10.104-tegra/kernel/drivers/usb/serial
- $sudo cp usb_wwan.ko /usr/lib/modules/5.10.104-tegra/kernel/drivers/usb/serial
- $sudo cp qcserial.ko /usr/lib/modules/5.10.104-tegra/kernel/drivers/usb/serial
完成后,加载.ko驱动模块并重启。
- $sudo depmod -a
- $sudo reboot
重启后,接入4G模块并查看查看驱动加载情况。
- $sudo modprobe usbmon // 加载usbmon驱动模块
- $sudo dmesg
- $lsmod
图10 dmesg查看USB驱动情况
图11 lsmod查看驱动情况
如果编译无误,则会出现如图10和11所示的情况。如果没有,则需要考虑重新编译。
接着我们使用串口调试工具minicom连接ttyUSB1,尝试对4G模块发送AT指令,测试结果如图12所示。
$sudo minicom -c on
图12 串口测试结果
图12中,可以看到AGX检测到4G模块并且成功识别了中国移动SIM卡。
将AGX连接显示屏后,发现在连接4G模块后会多出一个移动网络的标识符,如图13左所示。使用ping命令发现也可以连通,驱动移植成功。
图13 移动网络标识符(左)和ping命令结果(右)
[1] 移植EC20F 4G模块驱动基于Jetson-xavier-CSDN博客.
[2] 基于Xavier 移植移远EG25G 4G模块-CSDN博客.
[3] 移远EC20 4G模块Linux驱动移植和测试_ec25 4g模块驱动-CSDN博客.
[4] 4G模块 EC20 R2.0 USB Serial/GobiNet/QMI WWAN 驱动移植过程_qmi_wwan-CSDN博客.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。