MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)

我的上一篇文章中完成对MT7628固件的编译,本文是在固件编译通过的基础上移植EC20驱动的,固件编译问题请参考上文。

在讲解之前先介绍移远的EC20模块,该模块是目前较为成熟的4G模块,可向安装了Windows、Linux等设备的机器提供4G上网服务,移远同类产品中还有AG35模块,这个模块我之前在AM4378上移植过,当时花费了好多时间才移植成功,其实移远产品做得也不错,同类的模块移植方法基本是一样的。

废话不多说,下面开始讲述EC20驱动在MT7628上的移植过程。

 

第一步:

修改源码(注意:固件必须要先编译过一轮,否则没有build_dir目录)。此步骤必须细心修改,并认真核对。以下路径中的源文件均需要修改才能使用:

/home/user/openwrt-sdk/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/drivers/usb/serial/option.c

//大概在532行,添加如下代码
......

static const struct usb_device_id option_ids[] = {

#if 1 //Added by Quectel
	{ USB_DEVICE(0x05C6, 0x9090) }, /* Quectel UC15 */ 
	{ USB_DEVICE(0x05C6, 0x9003) }, /* Quectel UC20 */ 
	{ USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC25/EC20 R2.0 */
	{ USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */ 
	{ USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */ 
	{ USB_DEVICE(0x2C7C, 0x0191) }, /* Quectel EG91 */ 
	{ USB_DEVICE(0x2C7C, 0x0195) }, /* Quectel EG95 */
	{ USB_DEVICE(0x2C7C, 0x0306) }, /* Quectel EG06/EP06/EM06 */
	{ USB_DEVICE(0x2C7C, 0x0296) }, /* Quectel BG96 */
#endif
	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
......
//大概在1390行,插入以下代码
......

#ifdef CONFIG_PM
	.suspend           = usb_wwan_suspend,
	.resume            = usb_wwan_resume,
#if 1 //Added by Quectel
	.reset_resume = usb_wwan_resume, 
#endif

#endif
......
//在大约1459行,插入以下代码
......

	if (dev_desc->idVendor == cpu_to_le16(SAMSUNG_VENDOR_ID) &&
	    dev_desc->idProduct == cpu_to_le16(SAMSUNG_PRODUCT_GT_B3730) &&
	    iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
		return -ENODEV;
#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'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; 
//Quectel EC25&EC21&EC20 R2.0&EG91&EG95&EG06&EP06&EM06&BG96's interface 4 can be 
//used as USB Network device 
 if (serial->dev->descriptor.idVendor == cpu_to_le16(0x2C7C) 
 && 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);
......

/home/user/openwrt-sdk/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/drivers/usb/serial/qcserial.c

//大概在81行,注释以下代码

//{USB_DEVICE(0x05c6, 0x9215)},	/* Acer Gobi 2000 Modem device (VP413) */

/home/user/openwrt-sdk/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/drivers/net/usb/qmi_wwan.c

//大概在617行,注释以下代码

//{QMI_GOBI_DEVICE(0x05c6, 0x9215)},	/* Acer Gobi 2000 Modem device (VP413) */
//在大概436行,插入以下代码
......

static const struct usb_device_id products[] = {
	
#if 1 //Added by Quectel
#ifndef QMI_FIXED_INTF 
/* map QMI/wwan function by a fixed interface number */ 
#define QMI_FIXED_INTF(vend, prod, num) \ 
 .match_flags = USB_DEVICE_ID_MATCH_DEVICE | 
USB_DEVICE_ID_MATCH_INT_INFO, \ 
 .idVendor = vend, \ 
 .idProduct = prod, \ 
 .bInterfaceClass = 0xff, \ 
 .bInterfaceSubClass = 0xff, \ 
 .bInterfaceProtocol = 0xff, \ 
 .driver_info = (unsigned long)&qmi_wwan_force_int##num, 
#endif 
 { QMI_FIXED_INTF(0x05C6, 0x9003, 4) }, /* Quectel UC20 */ 
 { QMI_FIXED_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC25/EC20 R2.0 */
 { QMI_FIXED_INTF(0x2C7C, 0x0121, 4) }, /* Quectel EC21 */ 
{ QMI_FIXED_INTF(0x05C6, 0x9215, 4) }, /* Quectel EC20 */ 
{ QMI_FIXED_INTF(0x2C7C, 0x0191, 4) }, /* Quectel EG91 */
{ QMI_FIXED_INTF(0x2C7C, 0x0195, 4) }, /* Quectel EG95 */
{ QMI_FIXED_INTF(0x2C7C, 0x0306, 4) }, /* Quectel EG06/EP06/EM06 */
{ QMI_FIXED_INTF(0x2C7C, 0x0296, 4) }, /* Quectel BG96 */
#endif
......
//在文件的开头处插入如下代码
......

#include 
#include 

#if 1 //Added by Quectel 
#include  
struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) 
{ 
 if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C)) 
 return skb; 
 // Skip Ethernet header from message 
 if (skb_pull(skb, ETH_HLEN)) { 
 return skb; 
 } else { 
 dev_err(&dev->intf->dev, "Packet Dropped "); 
 } 
 // Filter the packet out, release it 
 dev_kfree_skb_any(skb); 
 return NULL; 
} 
#include  
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 )) 
static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 
{ 
 __be16 proto; 
 if (dev->udev->descriptor.idVendor != cpu_to_le16(0x2C7C)) 
 return 1;/* This check is no longer done by usbnet */ 
 if (skb->len < dev->net->hard_header_len) 
 return 0; 
 switch (skb->data[0] & 0xf0) { 
 case 0x40: 
 proto = htons(ETH_P_IP); 
 break; 
 case 0x60: 
 proto = htons(ETH_P_IPV6); 
 break; 
 case 0x00: 
 if (is_multicast_ether_addr(skb->data)) 
 return 1; 
 /* possibly bogus destination - rewrite just in case */ 
 skb_reset_mac_header(skb); 
 goto fix_dest; 
 default: 
 /* pass along other packets without modifications */ 
 return 1; 
 } 
 if (skb_headroom(skb) < ETH_HLEN) 
 return 0; 
 skb_push(skb, ETH_HLEN); 
 skb_reset_mac_header(skb); 
 eth_hdr(skb)->h_proto = proto; 
 memset(eth_hdr(skb)->h_source, 0, ETH_ALEN); 
fix_dest: 
 memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN); 
 return 1; 
} 
/* very simplistic detection of IPv4 or IPv6 headers */ 
static bool possibly_iphdr(const char *data) 
{ 
 return (data[0] & 0xd0) == 0x40; 
} 
#endif 
#endif
......
//在大概395行,插入如下代码
......

#if 1 //Added by Quectel
 if (dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) { 
 dev_info(&intf->dev, "Quectel EC25&EC21&EC20 R2.0&EG91&EG95&EG06&EP06&EM06&BG96 work on RawIP mode\n"); 
 dev->net->flags |= IFF_NOARP; 
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 )) 
 /* make MAC addr easily distinguishable from an IP header */ 
 if (possibly_iphdr(dev->net->dev_addr)) { 
 dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */ 
 dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ 
 } 
#endif 
 usb_control_msg( 
 interface_to_usbdev(intf), 
 usb_sndctrlpipe(interface_to_usbdev(intf), 0), 
 0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE 
 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE 
 1, //active CDC DTR 
 intf->cur_altsetting->desc.bInterfaceNumber, 
 NULL, 0, 100); 
 } 
#endif
......
//在大约504行,插入如下代码
......

static const struct driver_info	qmi_wwan_info = {
	.description	= "WWAN/QMI device",
	.flags		= FLAG_WWAN,
	.bind		= qmi_wwan_bind,
	.unbind		= qmi_wwan_unbind,
	.manage_power	= qmi_wwan_manage_power,
	.rx_fixup       = qmi_wwan_rx_fixup,
	
#if 1 //Added by Quectel 
	.tx_fixup = qmi_wwan_tx_fixup, 
#endif
......

/home/lusy/openwrt-sdk/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7628/linux-3.10.14/drivers/usb/serial/usb_wwan.c

//大概在460行,插入如下代码
......

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(0x05C6) && desc->idProduct == cpu_to_le16(0x9090)) 
urb->transfer_flags |= URB_ZERO_PACKET; 
 if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9003)) 
urb->transfer_flags |= URB_ZERO_PACKET; 
 if (desc->idVendor == cpu_to_le16(0x05C6) && desc->idProduct == cpu_to_le16(0x9215)) 
urb->transfer_flags |= URB_ZERO_PACKET; 
 if (desc->idVendor == cpu_to_le16(0x2C7C)) 
urb->transfer_flags |= URB_ZERO_PACKET; 
} 
#endif
	return urb;
......

 

第二步:

修改配置,在内核中添加一些选项来支持EC20。这里参考了别人的博客,网址如下:https://blog.csdn.net/hunzhangzui9837/article/details/85916965

#make menuconfig

Kernel modules->USB Support

照着图片配置就行。。。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第1张图片

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第2张图片

Network->

将以下选项编译进内核,但是我在我的make menuconfig中找不到wwan,先不管它,有就勾上。

wwan

chat

ppp

uqmi

Utilities->

将以下选项编译进内核,同样没找到comgt-ncm,不管它

comgt

comgt-ncm

usb-modeswitch

Luci->

1.Collections

luci

3.Applications

luci-app-multiwan

luci-app-qos

6.Protocols

luci-proto-3g

luci-proto-ppp

全都配置完了,开始编译

#make V=s

没有问题,全部编译成功。

 

第三步:

将编译好的固件烧入开发板。固件在/home/user/openwrt-sdk/bin/ramips路径下,名称为openwrt-ramips-mt7628-mt7628-squashfs-sysupgrade.bin。

启动开发板,先用

#ifconfig

查看一下当前ip地址,然后将ip地址复制到浏览器打开,即可通过LuCI登录板子进行配置。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第3张图片

选择如上图所示进入固件更新页面,进入如下页面

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第4张图片

在这个页面更新固件就可以了。

更新完成后,就可以将EC20通过USB插入开发板了,如果你的驱动移植成功,将会看到如下log:

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第5张图片

#cd /dev

查看一下是否有这几个文件。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第6张图片

 

第四步:

怎么通过4G模块上网。先进入LuCI页面。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第7张图片

如上图,进入接口配置。这里需要添加一个接口,下图已经添加好了,我下面教大家怎么添加。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第8张图片

点击Add new interface,名字自己起一个,选DHCP,选wwan0,如下图所示。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第9张图片

完成后记得修改一下这个接口的防火墙,如下图。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第10张图片

保存退出,最好板子也重启一下。

再次进入板子,输入

#ifconfig

就能看到你新加的接口了,4G网络正常的话这个接口应能获取到IP地址。

MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用)_第11张图片

#ping www.baidu.com

PING www.baidu.com (183.232.231.172): 56 data bytes
64 bytes from 183.232.231.172: seq=0 ttl=53 time=131.616 ms
64 bytes from 183.232.231.172: seq=1 ttl=53 time=107.725 ms
64 bytes from 183.232.231.172: seq=2 ttl=53 time=112.723 ms
64 bytes from 183.232.231.172: seq=3 ttl=53 time=113.865 ms

OK,大功告成!

 

 

你可能感兴趣的:(MT7628移植移远EC20驱动实现4G上网功能(绝大多数使用openwrt的设备通用))