赞
踩
我的上一篇文章中完成对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 <linux/usb/usbnet.h>
- #include <linux/usb/cdc-wdm.h>
-
- #if 1 //Added by Quectel
- #include <linux/etherdevice.h>
- 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 <linux/version.h>
- #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
照着图片配置就行。。。
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登录板子进行配置。
选择如上图所示进入固件更新页面,进入如下页面
在这个页面更新固件就可以了。
更新完成后,就可以将EC20通过USB插入开发板了,如果你的驱动移植成功,将会看到如下log:
#cd /dev
查看一下是否有这几个文件。
第四步:
怎么通过4G模块上网。先进入LuCI页面。
如上图,进入接口配置。这里需要添加一个接口,下图已经添加好了,我下面教大家怎么添加。
点击Add new interface,名字自己起一个,选DHCP,选wwan0,如下图所示。
完成后记得修改一下这个接口的防火墙,如下图。
保存退出,最好板子也重启一下。
再次进入板子,输入
#ifconfig
就能看到你新加的接口了,4G网络正常的话这个接口应能获取到IP地址。
#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,大功告成!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。