1. 程式人生 > >OpenWrt下通過EC20 R2.0 4G模組實現qmi撥號上網

OpenWrt下通過EC20 R2.0 4G模組實現qmi撥號上網

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

商家有詳細資料,價格合理,並且會提供相應的技術支援。