核心板移植移远4G模块EC20过程记录1-Gobinet

目录

一、背景

二、基本知识和调试思路

三、移植过程

3.1.1 USB串口驱动移植

(1)Add VID and PID

(2)Add the Zero Packet Mechanism

(3)Add Reset-resume Mechanism

(4)Increase the Quantity and Capacity of the Bulk Out URBs

(5)Use MBIM, GobiNet or QMI_WWAN Driver

(6)Modify Kernel Configuration

3.1.2 Gobinet拨号协议驱动移植

(1)Modify Source Codes of the Driver 添加源文件

(2)Modify Kernel Configuration 修改内核配置

3.1.3connect测试工具quectel的编译

(1)安装udhcpc和busybox软件包

(3)编译quectel-CM

(4)运行quectel-CM

一、背景

我司基于zhi xin的801核心板绘制了符合产品要求的底板,该底板有裕太YT8512的百兆网口、移远的EC20 4G模块以加密芯片和加密TF卡(都是国产芯片)。后两者是机密,此处不做说明。

目前核心板已经具备uboot 内核和文件系统,内核版本是ubuntu 4.14.155,调试串口和烧录USB口均可用。

我的职责是驱动调试。

二、基本知识和调试思路

EC20的驱动包括USB串口驱动和网卡驱动。前者对应原厂资料Quectel_Linux_USB_Serial_Option_Driver文件夹,后者对应Quectel_Linux&Android_GobiNet_Driver_V1.6.3文件夹。网卡驱动可选用GobiNet方式,或者QMI_WWAN方式,本文使用GobiNet。

调试的第一步是USB串口驱动OK,第二步是网卡驱动OK,第三步才是使用connect工具进行通信,即对应原厂QConnectManager_Linux_V1.6.2文件夹。

记着调试时一定要多请教驱动原厂和CPU厂商!!

三、移植过程

3.1、按照移远提供的指引一步一步来

3.1.1 USB串口驱动移植

(1)Add VID and PID

In order to recognize the module, the module’s VID and PID information as below need to be added to the file [KERNEL]/drivers/usb/serial/option.c

static const struct usb_device_id option_ids[] = {
#if 1 //Added by Quectel
{ USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20(MDM9215) */
{ USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC20(MDM9x07) R2.0/EC20 R2.1/EC25/EG25-G/EM05 */
{ USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21/EG21-G */
{ USB_DEVICE(0x2C7C, 0x0191) }, /* Quectel EG91 */
{ USB_DEVICE(0x2C7C, 0x0195) }, /* Quectel EG95 */
{ USB_DEVICE(0x2C7C, 0x0306) }, /* Quectel EG06/EP06/EM06 */
{ USB_DEVICE(0x2C7C, 0x0512) }, /* Quectel EG12/EM12/EG18 */
{ USB_DEVICE(0x2C7C, 0x0296) }, /* Quectel BG96 */
{ USB_DEVICE(0x2C7C, 0x0700) }, /* Quectel BG95/BG77/BG600L-M3/BC69 */
{ USB_DEVICE(0x2C7C, 0x0435) }, /* Quectel AG35 */
{ USB_DEVICE(0x2C7C, 0x0415) }, /* Quectel AG15 */
{ USB_DEVICE(0x2C7C, 0x0452) }, /* Quectel AG520R */
{ USB_DEVICE(0x2C7C, 0x0455) }, /* Quectel AG550R */
{ USB_DEVICE(0x2C7C, 0x0620) }, /* Quectel EG20 */
{ USB_DEVICE(0x2C7C, 0x0800) }, /* Quectel RG500Q/RM500Q/RG510Q/RM510Q */
#endif

这里注意:EC20有两种型号,MDM9215平台和MDM9x07,目前最新供货的芯片都是MDM9x07平台的,也许你拿到的芯片就旧的,你不确定是哪个型号,应该找厂家确认。为了防止其他PID和VID对调试结果的影响,可以只保留{ USB_DEVICE(0x2C7C, 0x0125) },其他的均可注释掉。

(2)Add the Zero Packet Mechanism

As required by the USB protocol, the mechanism for processing zero packets needs to be added during bulk-out transmission by adding the following statements.

针对内核版本大于2.6.34和小于2.6.34的系统,此处的处理有些许不一样,因为我用的是4.14.155,所以仅仅贴出这一部分的修改内容:

For Linux kernel version higher than 2.6.34, add the following statements to the file
[KERNEL]/drivers/usb/serial/usb_wwan.c

static struct urb *usb_wwan_setup_urb(struct usb_serial *serial, int endpoint,
 int dir, void *ctx, char *buf, int len,void (*callback) (struct urb *))
{
……
usb_fill_bulk_urb(urb, serial->dev,
                 usb_sndbulkpipe(serial->dev, endpoint) | dir,
                 buf, len, callback, ctx);
#if 1 //Added by Quectel for zero packet
    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;
    }
#endif
return urb;
}

这里注意:上述代码是文档《Quectel_LTE&5G_Linux_USB_Driver_User_Guide_V2.0》中所述,但是和原厂提供的源文件内容不一致:

	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 1 //Added by Quectel for Zero Packet
	if (dir == USB_DIR_OUT) {
		if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9090))
			urb->transfer_flags |= URB_ZERO_PACKET;
		if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9003))
			urb->transfer_flags |= URB_ZERO_PACKET;
		if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9215))
			urb->transfer_flags |= URB_ZERO_PACKET;
		if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C))
			urb->transfer_flags |= URB_ZERO_PACKET;
	}
#endif

原厂提供的源文件按照内核版本划分,上述代码是v4.14.111版本,和我当前版本相近。

我们到底以谁为准?分析代码可知:代码最内层有四个并列的if语句,其中只有desc->idVendor == cpu_to_le16(0x2C7C)才会生效,因为它是根据设备的VID值区分的,根据上一步可知,当前设备的VID是0x2C7C,因此我们只需保留最后一个if条件判断即可。

(3)Add Reset-resume Mechanism

Some USB host controllers/USB hubs will lose power or be reset when MCU enters the Suspend/Sleep mode, and cannot be used for USB resume after MCU exits from the Suspend/Sleep mode. The reset-resume mechanism needs to be enabled by adding the following statements.

For Linux kernel version higher than 3.4, add the following statements to the file [KERNEL]/drivers/usb/serial/option.c

内核大于3.4的这样改:

static struct usb_serial_driver option_1port_device = {
……
#ifdef CONFIG_PM
.suspend = usb_wwan_suspend,
.resume = usb_wwan_resume,
#if 1 //Added by Quectel
.reset_resume = usb_wwan_resume,
#endif
#endif
};

(4)Increase the Quantity and Capacity of the Bulk Out URBs

内核低于2.6.29的才需要此步

(5)Use MBIM, GobiNet or QMI_WWAN Driver

If MBIM, GobiNet or QMI_WWAN driver is required, add the following statements to prevent the module’s interface 4 from being used as a USB serial device.

使用GobiNet或者QMI_WWAN拨号上网的话,需要添加以下代码:

For Linux kernel version higher than 2.6.30, add the following statements to the file 
[KERNEL]/drivers/usb/serial/option.c

static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) {
struct usb_wwan_intf_private *data;
……
#if 1 //Added by Quectel
//Quectel modules’s interface 4 can be used as USB network device
 if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
     //some interfaces can be used as USB Network device (ecm, rndis, mbim)
     if (serial->interface->cur_altsetting->desc.bInterfaceClass != 0xFF) {
         return -ENODEV;
     }
     //interface 4 can be used as USB Network device (qmi)
     else if (serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4) {
         return -ENODEV;
     }
 }
#endif
/* Store device id so we can use it during attach. */
usb_set_serial_data(serial, (void *)id);
return 0;
}

这里要注意:上述代码是文档《Quectel_LTE&5G_Linux_USB_Driver_User_Guide_V2.0》中所述,但是和原厂提供的源文件内容不一致:

#if 1 //Added by Quectel
	//Quectel UC20's interface 4 can be used as USB Network device
	if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9003)
		&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
		return -ENODEV;

	//Quectel EC20(MDM9215)'s interface 4 can be used as USB Network device
	if (serial->dev->descriptor.idVendor == cpu_to_le16(0x05C6) && serial->dev->descriptor.idProduct == cpu_to_le16(0x9215)
		&& serial->interface->cur_altsetting->desc.bInterfaceNumber >= 4)
		return -ENODEV;

	if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {
		__u16 idProduct = le16_to_cpu(serial->dev->descriptor.idProduct);
		struct usb_interface_descriptor *intf = &serial->interface->cur_altsetting->desc;

		if (intf->bInterfaceClass != 0xFF || intf->bInterfaceSubClass == 0x42) {
			//ECM, RNDIS, NCM, MBIM, ACM, UAC, ADB
			return -ENODEV;
		}

		if ((idProduct&0xF000) == 0x0000) {
			//MDM interface 4 is QMI
			if (intf->bInterfaceNumber == 4 && intf->bNumEndpoints == 3
				&& intf->bInterfaceSubClass == 0xFF && intf->bInterfaceProtocol == 0xFF)
				return -ENODEV;
		}
	}
#endif

根据前面的分析,我们只需保留和0x2C7C相关的代码即可,并且通过加printk打印发现,0x2C7C的EC20,它的bInterfaceClass确实等于0xFF,.bInterfaceNumber 会等于0,1,2,3,而不会大于等于4的(bInterfaceNumber 应该就对应最终在/dev下生产的ttyusb0,ttyusb1,ttyusb2和ttyusb3)。所以以文档的代码为准,放弃源文件代码。

(6)Modify Kernel Configuration

cd <your kernel director>

        :进入内核目录。你应该在编译内核的系统中敲这些命令。有人在pc的虚拟机中编译内核,那么就在虚拟机中敲,如果你的开发板空间够大,可以直接编译内核那么久在arm板中敲。

export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabi

make bcmrpi_defconfig

        :设置设备架构是arm,交叉编译链。bcmrpi_defconfig是先使用内核默认的配置,bcmrpi_defconfig应该是树莓派板子默认的配置文件。我已经预先编译过内核了,所以不用再敲默认配置了。这些默认配置可以在内核目录/<your kernel director>/arch/arm/configs中找到。

make menuconfig

         :配置内核,按照下列层级找到USB driver for GSM and CDMA modems并按 Y将它编入内核。       

[*] Device Drivers →
        [*] USB Support →

                [*] USB Serial Converter support →
                        [*] USB driver for GSM and CDMA modems 

 make -j8

        :最后make一下,等待内核编译完成。最终在内核目录下能找到编译出来的内核镜像/<your kernel director>/arch/arm/boot/zImage

3.1.2 Gobinet拨号协议驱动移植

When the GobiNet driver has been installed in the module, a network device and a QMI channel will be created. The network device is named as ethX (usbX if the kernel version is 2.6.39 or lower) and the QMI channel is /dev/qcqmiX. The network device is used for data transmission, and QMI channel is used for QMI message interaction.
The following chapters explain how to integrate the GobiNet driver into the Linux operating system。

很奇怪,我的内核版本比较高,但是网卡驱动名却叫/dev/qcqmi0,不知道是不是有问题。

(1)Modify Source Codes of the Driver 添加源文件

The GobiNet driver is provided by Quectel in the form of the source file containing source codes. The source file should be copied to the file [KERNEL]/drivers/net/usb/ (or [KERNEL]/drivers/usb/net/ if the kernel version is lower than 2.6.22).

这里注意:原厂源码解压出来的是一个叫Gobinet的文件夹,指导文档的原意是复制所有源文件和头文件(其中的Makefile不要复制过去,它是编译模块使用的)到目录[KERNEL]/drivers/net/usb/下,而不是复制整个Gobinet文件夹(当然,你也可以复制文件夹,但是后续修改makefile时就不是按照文档的命令了)。

(2)Modify Kernel Configuration 修改内核配置

cd <your kernel director>

export ARCH=arm
export CROSS_COMPILE=arm-none-linux-gnueabi

make bcmrpi_defconfig

make menuconfig

这些命令和上述编译usb串口驱动的命令一致,不过勾选的选项不一致:

[*] Device Drivers → 
        -*- Network device support → 
                USB Network Adapters →
                        {*} Multi-purpose USB Networking Framework 

这里注意:当你敲y选中 Multi-purpose USB Networking Framework时,你会发现在它下面突然多处好多子选项,这些子选项我使用默认配置,没做修改。

 

 Please add the following statements to the file [KERNEL]/drivers/net/usb/Makefile (or 
[KERNEL]/drivers/usb/net/Makefile if the kernel version is lower than 2.6.22).

obj-y += GobiNet.o
GobiNet-objs := GobiUSBNet.o QMIDevice.o QMI.o

 最后一步在文件[KERNEL]/drivers/net/usb/Makefile的末尾追加上述编译命令,该命令将源码编入内核。

还记得前一步提到可以将Goninet这个文件夹的源码复制吗?其中的Makefile文件需要保留,做相应修改,我们就可以将驱动编译成ko模块,而不用编入内核了。

修改点有四处:

指定编译路径OUTPUTDIR,你们那里可能是 /[KERNEL]/drivers/net/usb/,指定内核路径KDIR;

指定设备架构ARCH,架构这个地方有一些逻辑判断,我都删除了,直接指定为arm

删除软连接ln -sf makefile Makefile,ln -sf在我的机器上运行时报错。软连接要不要都行。

最后的最后还是在内核的根目录下make -j8,等待一会内核镜像就出来了。

这里说明一下:你可以把usb串口驱动和Gobinet驱动一起加到内核中,最后一次make出来。

3.1.3connect测试工具quectel的编译

connect测试工具quectel-CM编译成单独的执行文件,和内核源码没有关系。它可以在任意路径下编译。

(1)安装udhcpc和busybox软件包

quectel-CM工具需要arm板上支持udhcpc命令。而udhcpc又依赖于busybox,所以通过dpkg -i命令安装busybox和udhcpc软件包。

下载地址:Index of /ubuntu-ports/pool/universe/b/busybox/

ssh连接到板子上,然后将软件包传进去,

dpkg -i busybox_1.27.2-2ubuntu3_armhf.deb

dpkg -i udhcpc_1.27.2-2ubuntu3_armhf.deb

两个软件的版本不一样要一致,但是对版本有依赖,注意一下。

(2)The source codes of “busybox udhpc” tool can be downloaded from https://busybox.net/, then enable CONFIG_UDHCPC with the command below and copy the script file [BUSYBOX]/examples/udhcp/simple.script to Linux board (renamed as /usr/share/udhcpc/default.script).
busybox menuconfig

需要下载busybox源码,然后敲busybox menuconfig。我执行失败了:

我觉得,已经通过软件包安装busybox和 udhcpc了,所以busybox源码啥的应该不需要了,只要busybox和 udhcpc命令能够使用即可。

(3)编译quectel-CM

解压原厂quectel-CM源码,放在系统的任意路径下,它里面有Makefile文件,我们先指定硬件架构和交叉编译链,再make,在当前目录下便可生成执行文件quectel-CM。

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-

make

(4)运行quectel-CM

通过ssh将quectel-CM文件传到板子上

./quectel-CM &

直接执行。

理想效果是这样的:

root@cqh6:~# ./quectel-CM/quectel-CM &
[07-03_06:56:28:172] WCDMA&LTE_QConnectManager_Linux&Android_V1.3.4
[07-03_06:56:28:172] ./quectel-CM/quectel-CM profile[1] = (null)/(null)/(null)/0, pincode = (null)
[07-03_06:56:28:174] Find /sys/bus/usb/devices/2-1.2 idVendor=2c7c idProduct=0512
[07-03_06:56:28:174] Find /sys/bus/usb/devices/2-1.2:1.4/net/wwan0
[07-03_06:56:28:174] Find usbnet_adapter = wwan0
[07-03_06:56:28:175] Find /sys/bus/usb/devices/2-1.2:1.4/usbmisc/cdc-wdm0
[07-03_06:56:28:175] Find qmichannel = /dev/cdc-wdm0
[07-03_06:56:28:197] cdc_wdm_fd = 7
[07-03_06:56:28:381] Get clientWDS = 18
[07-03_06:56:28:445] Get clientDMS = 1
[07-03_06:56:28:509] Get clientNAS = 2
[07-03_06:56:28:573] Get clientUIM = 2
[07-03_06:56:28:637] Get clientWDA = 1
[07-03_06:56:28:701] requestBaseBandVersion EM12GPAR01A06M4G
[07-03_06:56:28:957] requestGetSIMStatus SIMStatus: SIM_READY
[07-03_06:56:29:021] requestGetProfile[1] cmnet///0
[07-03_06:56:29:085] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[07-03_06:56:29:149] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[07-03_06:56:29:277] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[07-03_06:56:29:341] requestSetupDataCall WdsConnectionIPv4Handle: 0x127b42c0
[07-03_06:56:29:469] requestQueryDataCall IPv4ConnectionStatus: CONNECTED
[07-03_06:56:29:533] ifconfig wwan0 up
[07-03_06:56:29:543] busybox udhcpc -f -n -q -t 5 -i wwan0
udhcpc: started, v1.27.2
udhcpc: sending discover
udhcpc: sending select for 10.170.235.201
udhcpc: lease of 10.170.235.201 obtained, lease time 7200
[07-03_06:56:29:924] /etc/udhcpc/default.script: Resetting default routes
[07-03_06:56:29:936] /etc/udhcpc/default.script: Adding DNS 211.138.180.2

而我的结果是这样的:

root@scm801:/home# ./quectel-CM &
[1] 500
root@scm801:/home# [12-10_09:49:46:582] QConnectManager_Linux_V1.6.2
[12-10_09:49:46:583] Find /sys/bus/usb/devices/2-1 idVendor=0x2c7c idProduct=0x125, bus=0x002, dev=0x002
[12-10_09:49:46:584] Auto find qmichannel = /dev/qcqmi0
[12-10_09:49:46:584] Auto find usbnet_adapter = usb0
[12-10_09:49:46:585] netcard driver = GobiNet, driver version = V1.6.3
[12-10_09:50:01:796] ioctl(0x89f3, qmap_settings) errno:2 (No such file or directory), rc=-1
[12-10_09:50:01:796] Modem works in QMI mode
[12-10_09:50:17:156] Failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:50:17:156] failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:50:32:516] Failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:50:32:516] failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:50:47:876] Failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:50:47:876] failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:51:03:236] Failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:51:03:236] failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:51:18:596] Failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:51:18:596] failed to open /dev/qcqmi0, errno: 2 (No such file or directory)
[12-10_09:51:18:597] GobiNetSendQMI QMIType: 2 has no clientID
[12-10_09:51:18:597] requestBaseBandVersion err = -19
[12-10_09:51:18:597] GobiNetSendQMI QMIType: 26 has no clientID
[12-10_09:51:18:597] requestSetEthMode err = -19
[12-10_09:51:18:598] GobiNetSendQMI QMIType: 11 has no clientID
[12-10_09:51:18:598] requestGetSIMStatus err = -19
[12-10_09:51:18:598] GobiNetSendQMI QMIType: 1 has no clientID
[12-10_09:51:18:598] requestGetProfile err = -19
[12-10_09:51:18:599] GobiNetSendQMI QMIType: 3 has no clientID
[12-10_09:51:18:599] requestRegistrationState2 err = -19
[12-10_09:51:18:599] GobiNetSendQMI QMIType: 1 has no clientID
[12-10_09:51:18:599] requestQueryDataCall err = -19
[12-10_09:51:18:600] ifconfig usb0 0.0.0.0
[12-10_09:51:18:614] ifconfig usb0 down

该问题待查,已经提交给移远研发部门。

后续结果,我会更新该博文。

原厂文档代码以及本文涉及的软件包已经传上我的CSDN:busybox_1.27.2-2ubuntu3_armhf软件包和源码压缩包-Linux文档类资源-CSDN下载

以上主要参考移远原厂给的参考资料

Ubuntu Server 18.04 中 EC20 驱动 移植 Gobinet 拨号 - 灰信网(软件开发博客聚合)

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汉尼拔勇闯天涯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值