AR9331 Newifi3路由挂载移远EC20、EC21、EC25、AG35等4G驱动示例步骤讲解
1、开发环境
开发板:AR9331 Newifi3等
源码版本:Openwrt(源码地址:https://git.lede-project.org/source.git)
源码编译宿主系统:ubuntu12.04 ubuntu14.04(vm虚拟机)
4G模块:移远EC20 EC20 EC25 AG35等
参考文档:Quectel_WCDMA< E_Linux_USB_Driver_User_Guide_V1.7.pdf
2、步骤
【说明】虽然大家开发板型号不一,有AR、RT、MT版本;源码也有CC、LEDE、潘多拉、老毛子的不同;但是挂载4G驱动的方法都一样。
目前EC20和EC25对路由器最兼容,现在我是Openwrt最新版本的,兼容性完美,QMI拨号非常稳定。
2.1 USB Serial驱动
当4G模块连接到USB串行驱动时,驱动程序将在目录/dev中创建设备文件,
ttyUSB0/ttyUSB1/ttyUSB2/ttyUSB3/ttyUSB4
下图为各个4G模块 /ttyUSB的功能
我们的目的是需要cdc-wdm0 这个设备文件
接下来就是讲解如何移植USB Serial。
2.1.1 增加PID&VID
要想识别模块,客户应该在下面添加模块维和PID信息(支持EC20、EC20、EC25、AG35等4G模块)
File: [KERNEL]/drivers/usb/serial/option.c
比如AR9331的KERNEL目录在build_dir/target-mips_24kc_musl/linux-ar71xx_generic/linux-4.4.79
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 */
{ 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 */
{ USB_DEVICE(0x2C7C, 0x0435) }, /* Quectel AG35 */
#endif
【注】只添加#if 1 到 #endif的内容,具体位置添加位置需要读者自己注意。
2.1.2 添加零包处理
根据USB协议的要求,客户需要添加处理零数据包的机制。
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 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;
}
2.1.3 增加休眠后唤醒接口
当MCU进入暂停/休眠模式时,一些USB主机控制器/USB集线器将失去电源或重新设置,并且在MCU退出暂停/休眠模式后,它们不能恢复USB设备。请添加以下语句以启用重新设置恢复过程。
For Linux kernel version higher than 3.4:
File: [KERNEL]/drivers/usb/serial/option.c
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
};
2.1.4 使用 GobiNet or QMI WWAN
如果客户使用ucxx/ec2x/egxx/EP06/EM06/BG96/AG35,并要求GobiNet或QMI WWAN,请添加以下语句,以防止这些模块接口4被用作USB串行设备。
For Linux Kernel Version newer than 2.6.30:
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'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&EG91&EG95&EG06&EP06&EM06&BG96/AG35'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);
return 0;
}
2.2 QMI WWAN驱动
2.2.1 Add VID and PID
QMI WWAN driver source file is [KERNEL]/drivers/net/usb/qmi_wwan.c.
File: [KERNEL]/drivers/net/usb/qmi_wwan.c
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 */
{ 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 */
{ QMI_FIXED_INTF(0x2C7C, 0x0435, 4) }, /* Quectel AG35 */
#endif
2.2.2 Add Support for Raw IP Mode
File: [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, 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
……
/* if follow function exist, modify it as 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
EC25&EC21&EG91&EG95&EG06&EP06&EM06&BG96&AG35 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
err:
return status;
}
……
/* if follow function exist, modify it as below */
static int qmi_wwan_bind_shared(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 EC25&EC21&
EG91&EG95&EG06&EP06&EM06&BG96&AG35 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
err:
return status;
}
……
/* if follow struct exist, modify it as below */
static const struct driver_info qmi_wwan_info =
{
……
#if 1 //Added by Quectel
.tx_fixup = qmi_wwan_tx_fixup,
.rx_fixup = qmi_wwan_rx_fixup,
#endif
}
……
/* if follow struct exist, modify it as below */
static const struct driver_info qmi_wwan_force_int4 = {
……
#if 1 //Added by Quectel
.tx_fixup = qmi_wwan_tx_fixup,
.rx_fixup = qmi_wwan_rx_fixup,
#endif
};
/* if follow struct exist, modify it as below */
static const struct driver_info qmi_wwan_shared = {
……
#if 1 //Added by Quectel
.tx_fixup = qmi_wwan_tx_fixup,
.rx_fixup = qmi_wwan_rx_fixup,
#endif
};
2.3 修改配置
第一步:进入配置环境
$make menuconfig
第二步:配置
Kernel modules >>
USB Support >>
<*> Kmod -usb-core
-*-Kmod -usb-net
-*- kmod-usb-net-cdc-ether
<*> kmod-usb-net-cdc-mbim
-*- kmod-usb-net-cdc-ncm
<*> kmod-usb-net-cdc-subset
<*>kmod-usb-net-qmi-wwan
<*>Kmod-usb-ohci //这个选项一定要勾选,否则可能无法在系统中查看设备
<*>Kmod-usb-serial
<*>Kmod-usb-serial-option
<*>Kmod-usb-serial-wwan
<*>kmod-usb-uhci
<*>Kmod-usb2
NetWork >>
<*> wwan
<*>chat
<*>ppp
<*>uqmi
Utilities
-*- comgt
<*> comgt-ncm
<*>usb-modeswitch
Luci
1. Collections
<*> luci
3. Applications
<*> luci-app-multiwan (optional to support multiple 3g dongles)
<*> luci-app-qos (optional to provide QOS support)
6. Protocols
<*> luci-proto-3g
-*- luci-proto-ppp
2.4 编译测试
以上操作完成后就是编译源码了。
$ make V=s
将编译好固件烧写进入板子中,插入4G模块,在dev目录下查看,就会出现cdc-wdm0 这个设备文件
有以上信息表示驱动配置成功,接下来就拨号了。
3.5 拨号上网
3.5.1 安装交叉编译工具
进入源码目录,执行mkae menuconfig
cd lede_source
make menuconfig
选中Toolchain
保存,编译
make V=99
找到交叉工具链的位置:
这里我们演示将交叉工具链安装到 ubuntu 的“/opt”目录下。 首先切换到 openwrt 源码的根目录下,输入如下命令:
cd ~/lede_source/bin/targets/ramips/mt7621
sudo tar xjvf openwrt-toolchain-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64.tar.bz2 -C /opt
最后,设置环境变量
sudo vi /etc/bash.bashrc
在最后一行添加
export PATH=/opt/openwrt-toolchain-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64/toolchain-mipsel_24kc_gcc-7.4.0_musl/bin:$PATH
export STAGING_DIR=/your_openwrt_path/staging_dir
《注意》上面这个“STAGING_DIR”变量中的“your_openwrt_path”是读者实际放 openwrt源码的根目录,如果“STAGING_DIR”变量不设置的话,会在用交叉工具链编译文件时有警告,但是不影响编译结果。最后保存退出。接着在终端执行以下命令:
source /etc/bash.bashrc
测试是否安装成功:
mipsel-openwrt-linux-gcc -v
3.5.2 编译拨号应用程序
拨号程序仍然使用移远提供的quectel-CM(下载地址在文章末尾),这是一个4G连接管理程序,这里没什么说的,执行:
$mipsel-openwrt-linux-musl-gcc *.c -o quectel-CM -lpthread –ldl
【注】也可将quectel-CM下的Makefile文件修改成如下,然后 make
CROSS-COMPILE:= mips-openwrt-linux- #AR9331开发板的交叉编译工具(其他的自行修改)
CC:=$(CROSS-COMPILE)gcc
LD:=$(CROSS-COMPILE)ld
release: clean
$(CC) -Wall -s QmiWwanCM.c GobiNetCM.c main.c MPQMUX.c QMIThread.c util.c udhcpc.c -o quectel-CM -lpthread -ldl
debug: clean
$(CC) -Wall -g QmiWwanCM.c GobiNetCM.c main.c MPQMUX.c QMIThread.c util.c udhcpc.c -o quectel-CM -lpthread -ldl
clean:
rm -rf quectel-CM *~
【注】移远提供的拨号程序下载地址在文章末尾(包含参考文档)。
交叉编译后得到可执行文件:“quectel-CM” ,然后将quectel-CM可执行文件用wincp软件拷贝到AR9331开发板中,执行:
chmod 777 quectel-CM #先改变权限
./quectel-CM &
出现如下效果,说明拨号成功:
接下来ping一下百度首页地址,看是否可以联网。
说明测试成功,开发板可以上网了。
3.6 后续问题
问题1:能ping通百度IP地址,无法ping通其域名www.baidu.com
这里需要添加DNS解析服务器的地址,在/etc目录配置resolv.conf文件添加DNS客户,它包含了主机的域名搜索顺序和DNS服务器的地址。开发板执行:
vim /etc/resolv.conf
编辑内容:
nameserver 114.114.114.114 #国内的DNS
nameserver 8.8.8.8 #国外的DNS
接下来,ping www.baidu.com
问题2:路由器能上网后,其他设备连接此路由器不能上网
ifconfig -a 看是否有wwan0这个端口
问题2:路由器能上网后,其他设备连接此路由器不能上网
ifconfig -a 看是否有wwan0这个端口
然后修改配置文件
vim /etc/config/network
添加如下内容:
config interface 'wan'
option device '/dev/cdc-wdm0'
option proto 'qmi'
option apn 'cnnet'
option username 'card'
option password 'card'
option ifname 'wwan0'
登录到路由器web界面,点击网路下的接口,也就是network下的interface,会发现有这么一个设备,点击连接
到此为止,4G路由器就搞定了。
【附】移远提供的拨号程序和参考文档下载地址:https://download.csdn.net/download/hunzhangzui9837/10899023
- 分享
- 举报
-
浏览量:3438次2019-12-05 18:03:06
-
浏览量:4796次2022-10-14 08:34:42
-
浏览量:1259次2024-01-12 15:17:33
-
浏览量:32711次2022-06-11 11:06:24
-
浏览量:2315次2020-02-27 10:32:59
-
浏览量:7820次2021-06-09 14:49:23
-
浏览量:4361次2019-07-22 17:43:59
-
浏览量:1952次2018-12-29 15:54:40
-
浏览量:2379次2020-09-21 19:12:37
-
浏览量:1481次2020-02-26 19:46:35
-
浏览量:860次2023-11-21 17:56:50
-
浏览量:4813次2020-08-19 22:25:39
-
浏览量:3014次2020-08-29 21:36:16
-
浏览量:2672次2022-03-01 09:00:32
-
浏览量:2455次2019-09-26 11:59:59
-
浏览量:10029次2022-11-10 18:07:40
-
浏览量:1885次2019-08-20 16:51:26
-
浏览量:2214次2018-11-07 15:37:30
-
浏览量:5350次2021-04-06 14:54:49
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
Mrs Wu
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明