OpenWrt下通过EC20 R2.0 4G模块实现qmi拨号上网

  • Post author:
  • Post category:其他


OpenWrt下通过EC20R2.0 4G模块实现qmi拨号上网


1.本文档参考资料为Quectel_WCDMA&LTE_Linux_USB_Driver_User_Guide_V1.6.pdf,


实现QMI拨号,只需要参考下列章节即可



EC20有多个版本,看是否是

EC20 R2.0


还是普通


EC20





2.修改内核代码


修改USB串口驱动

File : [KERNEL]/drivers/usb/serial/option.c

staticconst 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(0x05C6, 0x9215) }, /* Quectel EC20 */


{ USB_DEVICE(0x2C7C, 0x0125) }, /* Quectel EC25/EC20 R2.0 */


{ USB_DEVICE(0x2C7C, 0x0121) }, /* Quectel EC21 */


#endif


2.1.1  . Add the Zero PacketMechanism

For Linux Kernel Version newer than 2.6.34:

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 Quectelfor 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;

}


2.1.2. Add Reset Resume

File: [KERNEL]/drivers/usb/serial/option.c

static struct usb_serial_driveroption_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

}


2.2.5  Use GobiNet or QMI WWAN

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 UC20’sinterface 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 interface4 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;


//QuectelEC21&EC25&EC20 R2.0’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 duringattach. */

usb_set_serial_data(serial, (void *)id);

return 0;

}


3. QMI WWAN Driver


3.1.1 Add VID and PID

fileis “[KERNEL]/drivers/net/usb/qmi_wwan.c”.

static const struct usb_device_idproducts[] = {


#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(0x05C6, 0x9215, 4) }, /* Quectel EC20 */


{ QMI_FIXED_INTF(0x2C7C, 0x0125, 4) }, /* Quectel EC25/EC20R2.0 */


{ QMI_FIXED_INTF(0x2C7C, 0x0121, 4) }, /* Quectel EC21 */


#endif




3.1.2  Add Support for Raw IP Modefor EC21/EC25/EC20 R2.0

file is”[KERNEL]/drivers/net/usb/qmi_wwan.c”

#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, structsk_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, structsk_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 IPv4or IPv6 headers */

static bool possibly_iphdr(const char*data)

{

return (data[0] & 0xd0) == 0x40;

}

#endif

#endif

/* if follow function exist, modify itas below */

static int qmi_wwan_bind(struct usbnet*dev, struct usb_interface *intf)

{

……


#if 1 //Added by Quectel


if(dev->udev->descriptor.idVendor == cpu_to_le16(0x2C7C)) {


dev_info(&intf->dev, “Quectel EC21&EC25&EC20 R2.0work 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 CDCDTR


intf->cur_altsetting->desc.bInterfaceNumber,


NULL, 0, 100);


}


#endif

err:

return status;

}

/* if follow struct exist, modify itas below */

static const struct driver_info  qmi_wwan_info =

{

……


#if 1 //Added by Quectel


#if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,5,0 ))


.tx_fixup =qmi_wwan_tx_fixup,


#endif


#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))


.rx_fixup =qmi_wwan_rx_fixup,


#endif


#endif

}

/* if follow struct exist, modify itas below */

static const struct driver_infoqmi_wwan_force_int4 = {

……


#if 1 //Added by Quectel


#if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,5,0 ))


.tx_fixup =qmi_wwan_tx_fixup,


#endif


#if (LINUX_VERSION_CODE < KERNEL_VERSION( 3,9,1 ))


.rx_fixup =qmi_wwan_rx_fixup,


#endif


#endif

};

配置选择:

NetWork   >>

wwan               …………………GenericOpenWrt 3G/4G proto handler

Kernel modules >>

USB Support >>

Kmod -usb-core

Kmod -usb-net

>> kmod-usb-net-qmi-wwan


Kmod-usb-ohci     //


这个选项一定要勾选,否则可能无法在系统中查看设备

Kmod-usb-serial

Kmod-usb-serial-option

Kmod-usb-serial-wwan

kmod-usb-uhci

Kmod-usb2

成功过后,可以看到Openwrt系统启动打印信息,

查看dev下设备号 ls /dev

出现以上信息,表示驱动正常,下面可以启动拨号软件进行拨号。

编译在openwrt终端上可执行的

EC20R2.0

拨号程序quectel-CM

将Quectel_Linux_ConnectManager_SR01A01V21.zip进行解压,将文件下的quectel-CM交叉编译,编译为在板子openwrt15.05下可执行文件。(

以下操作都是在非root

用户下操作的)


1.交叉编译工具链编译的时报没有STAGING_DIR,它在ubuntu上的openwrt的目录下

openwrt/staging_dir ,在ubuntu上键入下面命令

exportSTAGING_DIR=/home/sanliang/workspace/openwrt/staging_dir



2.设置交叉工具链的环境变量

PATH=$PATH:/home/sanliang/workspace/openwrt1/openwrt/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin


注意在这个bin

下是含有我们的mipsel-openwrt-linux-gcc编译工具的


3.将quectel-CM下的Makefile文件修改成如下,然后 make

CROSS-COMPILE:=mipsel-openwrt-linux-


得到可在openwrt下可执行的quectel-CM文件。

4.将quectel-CM文件上传到板子上,给予可执行权限 chmod  777  quectel-CM

后台运行:     ./quectel-CM   &

拨号成功打印信息如下:


5.添加DNS解析服务器的地址

现在已经拨号成功,但是可能无法pingwww.baidu.com,但是可以直接ping 百度的IP,这   需要设置/etc/resolv.conf来添加DNS解析服务器的地址,文件/etc/resolv.conf配置DNS客户,          它包含了主机的域名搜索顺序和DNS服务器的地址,每一行应包含一个关键字和一个或多     个的由空格隔开的参数。

我这里只设置了两个DNS,如下:

nameserver114.114.114.114

nameserver8.8.8.8

再次pingwww.baidu.com  ,发现已经可以ping 通域名了

本文由三良整理

EC20购买地址:

https://item.taobao.com/item.htm?spm=a1z1r.7974869.0.0.547a2b0jhr5eu&id=543786541430

商家有详细资料,价格合理,并且会提供相应的技术支持。



版权声明:本文为qq_17351077原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。